Skip to content

8. Ejercicio de aplicación – versión 1

8.1. El problema

Image

La tabla anterior permite calcular el impuesto en el caso simplificado de un contribuyente que solo tiene que declarar su salario. Como indica la nota (1), el impuesto así calculado es el impuesto antes de aplicar tres mecanismos:

  • el límite máximo del coeficiente familiar, que se aplica a los ingresos altos;
  • la bonificación y la reducción de impuestos que se aplican a los ingresos bajos;

Por lo tanto, el cálculo del impuesto comprende los siguientes pasos [http://impotsurlerevenu.org/comprendre-le-calcul-de-l-impot/1217-calcul-de-l-impot-2019.php]:

Image

Nos proponemos escribir un programa que permita calcular el impuesto de un contribuyente en el caso simplificado de un contribuyente que solo tenga que declarar su salario:

8.1.1. Cálculo del impuesto bruto

El impuesto bruto se puede calcular de la siguiente manera:

Primero se calcula el número de partes del contribuyente:

  • cada padre aporta 1 parte;
  • los dos primeros hijos aportan cada uno 1/2 parte;
  • los hijos siguientes aportan una parte cada uno:

Por lo tanto, el número de partes es:

  • nbParts = 1 + nbEnfants * 0,5 + (nbEnfants - 2) * 0,5 si el empleado no está casado;
  • nbParts = 2 + nbEnfants * 0,5 + (nbEnfants - 2) * 0,5 si está casado;
    • donde nbEnfants es su número de hijos;
  • se calcula el ingreso imponible R = 0,9 * S, donde S es el salario anual;
  • se calcula el cociente familiar QF = R / nbParts;
  • se calcula el impuesto bruto I según los siguientes datos (2019):
9964
0
0
27519
0,14
1394,96
73 779
0,3
5798
156 244
0,4
13 913,69
0
0,45
20163,45

Cada línea tiene 3 campos: champ1, champ2, champ3. Para calcular el impuesto I, se busca la primera línea en la que QF ≤ campo1 y se toman los valores de esa línea. Por ejemplo, para un empleado casado con dos hijos y un salario anual S de 50 000 euros:

Ingreso imponible: R = 0,9 * S = 45 000

Número de cuotas: nbParts = 2 + 2 * 0,5 = 3

Cotizante familiar: QF = 45 000 / 3 = 15 000

La primera línea en la que QF <= campo1 es la siguiente:

    27519    0.14    1394.96

El impuesto I es, por lo tanto, igual a 0,14*R – 1394,96*nbParts = [0,14*45000-1394,96*3] = 2115. El impuesto se redondea al euro inferior.

Si la relación QF <= campo1 se cumple desde la primera línea, entonces el impuesto es cero.

Si QF es tal que la relación QF <= campo1 nunca se cumple, entonces se utilizan los coeficientes de la última línea. En este caso:

    0    0.45    20163.45

lo que da como resultado el impuesto bruto I = 0,45*R – 20 163,45*nbParts.

8.1.2. Límite máximo del cociente familiar

Image

Para saber si se aplica el límite máximo del cociente familiar QF, se vuelve a calcular el impuesto bruto sin los hijos. Siguiendo con el ejemplo del empleado casado con dos hijos y un salario anual S de 50 000 euros:

Ingreso imponible: R = 0,9 * S = 45 000

Número de partes: nbParts = 2 (ya no se cuentan los hijos)

Cotiente familiar: QF = 45 000 / 2 = 22 500

La primera línea en la que QF <= campo1 es la siguiente:

    27519    0.14    1394.96

El impuesto I es, por lo tanto, igual a 0,14*R – 1394,96*nbParts = [0,14*45000-1394,96*2] = 3510.

Ganancia máxima relacionada con los hijos: 1551 * 2 = 3102 euros

Impuesto mínimo: 3510 – 3102 = 408 euros

El impuesto bruto con 3 partes, ya calculado en 2115 euros, es mayor que el impuesto mínimo de 408 euros, por lo que el límite familiar no se aplica en este caso.

En general, el impuesto bruto es mayor que (impuesto1, impuesto2), donde:

  • [impôt1]: es el impuesto bruto calculado con los hijos;
  • [impôt2]: es el impuesto bruto calculado sin los hijos y menos la deducción máxima (en este caso, 1551 euros por media parte) relacionada con los hijos;

8.1.3. Cálculo de la reducción

Image

Siguiendo con el ejemplo del empleado casado con dos hijos y un salario anual S de 50 000 euros:

El impuesto bruto (2115) obtenido en el paso anterior es inferior a 2627 euros para una pareja (1595 euros para una persona soltera): por lo tanto, se aplica la reducción. Se obtiene mediante el siguiente cálculo:

descuento = umbral (pareja = 1970 / soltero = 1196) - 0,75 * Impuesto bruto

descuento = 1970 - 0,75 × 2115 = 383,75, redondeado a 384 euros.

Nuevo impuesto bruto = 2115 - 384 = 1731 euros

8.1.4. Cálculo de la reducción de impuestos

Image

Por debajo de cierto umbral, se aplica una reducción del 20 % sobre el impuesto bruto resultante de los cálculos anteriores. En 2019, los umbrales son los siguientes:

  • soltero: 21 037 euros;
  • pareja: 42 074 euros; (la cifra de 37 968 utilizada en el ejemplo anterior parece errónea);

Este umbral se incrementa en el valor: 3797 * (número de medias partes aportadas por los hijos).

Siguiendo con el ejemplo del empleado casado con dos hijos y un salario anual S de 50 000 euros:

  • su ingreso imponible (45 000 euros) es inferior al umbral (42 074 + 2 × 3797) = 49 668 euros;
  • por lo tanto, tiene derecho a una reducción del 20 % de su impuesto: 1731 * 0,2 = 346,2 euros, redondeado a 347 euros;
  • el impuesto bruto del contribuyente queda en: 1731 - 347 = 1384 euros;

8.1.5. Cálculo del impuesto neto

Nuestro cálculo terminará aquí: el impuesto neto a pagar será de 1384 euros. En la realidad, el contribuyente puede beneficiarse de otras reducciones, en particular por donaciones a organizaciones de interés público o general.

8.1.6. Caso de los ingresos altos

Nuestro ejemplo anterior corresponde a la mayoría de los casos de asalariados. Sin embargo, el cálculo del impuesto es diferente en el caso de los ingresos elevados.

8.1.6.1. Límite máximo de la reducción del 10 % sobre los ingresos anuales

En la mayoría de los casos, el ingreso imponible se calcula mediante la fórmula: R = 0,9 * S, donde S es el salario anual. A esto se le llama la reducción del 10 %. Esta reducción tiene un límite máximo. En 2019:

  • no puede ser superior a 12 502 euros;
  • no puede ser inferior a 437 euros;

Tomemos el caso de un empleado soltero sin hijos y con un salario anual de 200 000 euros:

  • la reducción del 10 % es de 20 000 euros > 12 502 euros. Por lo tanto, se reduce a 12 502 euros;

8.1.6.2. Límite máximo del cociente familiar

Consideremos un caso en el que se aplica el límite máximo familiar mencionado en el párrafo |Límite máximo del cociente familiar|. Tomemos el caso de una pareja con tres hijos y ingresos anuales de 100 000 euros. Repasemos los pasos del cálculo:

  • la deducción del 10 % es de 10 000 euros < 12 502 euros. Por lo tanto, el ingreso imponible R es 100 000 - 10 000 = 90 000 euros;
  • la pareja tiene nbParts = 2 + 0,5 × 2 + 1 = 4 partes;
  • por lo tanto, su cociente familiar es QF = R / nbParts = 90 000 / 4 = 22 500 euros;
  • su impuesto bruto I1 con hijos es I1 = 0,14 × 90 000 − 1 394,96 × 4 = 7 020 euros;
  • su impuesto bruto I2 sin hijos:
  • QF = 90 000 / 2 = 45 000 euros;
  • I2 = 0,3 × 90 000 − 5 798 × 2 = 15 404 euros;
  • la regla del límite máximo del coeficiente familiar establece que el beneficio que aportan los hijos no puede superar (1551 × 4 medias partes) = 6204 euros. Sin embargo, en este caso es I2-I1 = 15 404 - 7 020 = 8 384 euros, por lo que es superior a 6 204 euros;
  • por lo tanto, el impuesto bruto se vuelve a calcular como I3 = I2-6204 = 15 404 - 6 204 = 9 200 euros;

Esta pareja no tendrá ni descuento ni reducción, y su impuesto final será de 9200 euros.

8.1.7. Cifras oficiales

El cálculo del impuesto es complejo. A lo largo de este documento, las simulaciones se realizarán con los siguientes ejemplos. Los resultados provienen del simulador de la administración tributaria |https://www3.impots.gouv.fr/simulateur/calcul_impot/2019/simplifie/index.htm|:

Contribuyente
Resultados oficiales
Resultados del algoritmo del documento
Pareja con 2 hijos y ingresos anuales de 55 555 euros
Impuesto = 2815 euros
Tasa impositiva = 14 %
Impuesto = 2814 euros
Tasa impositiva = 14 %
Pareja con dos hijos y ingresos anuales de 50 000 euros
Impuesto = 1385 euros
Descuento = 720 euros
Reducción = 0 euros
Tasa impositiva = 14 %
Impuesto = 1384 euros
Descuento = 384 euros
Descuento = 347 euros
Tasa impositiva = 14 %
Pareja con 3 hijos y ingresos anuales de 50 000 euros
Impuesto = 0 euros
Descuento = 384 euros
Descuento = 346 euros
Tasa impositiva = 14 %
Impuesto = 0 euros
Descuento = 720 euros
Reducción = 0 euros
Tasa impositiva = 14 %
Soltero con 2 hijos y ingresos anuales de 100 000 euros
Impuesto = 19 884 euros
Descuento = 0 euros
Descuento = 0 euros
Tasa impositiva = 41 %
Impuesto = 19 884 euros
Recargo = 4480 euros
descuento = 0 euros
Reducción = 0 euros
Tasa impositiva = 41 %
Soltero con 3 hijos y ingresos anuales de 100 000 euros
Impuesto = 16 782 euros
Descuento = 0 euros
Descuento = 0 euros
Tasa impositiva = 41 %
Impuesto = 16 782 euros
Recargo = 7176 euros
descuento = 0 euros
Reducción = 0 euros
Tasa impositiva = 41 %
Pareja con 3 hijos y ingresos anuales de 100 000 euros
Impuesto = 9200 euros
Descuento = 0 euros
Descuento = 0 euros
Tasa impositiva = 30 %
Impuesto = 9200 euros
Recargo = 2180 euros
descuento = 0 euros
Reducción = 0 euros
Tasa impositiva = 30 %
Pareja con 5 hijos y ingresos anuales de 100 000 euros
Impuesto = 4230 euros
Descuento = 0 euros
Descuento = 0 euros
Tasa impositiva = 14 %
Impuesto = 4230 euros
Descuento = 0 euros
Descuento = 0 euros
Tasa impositiva = 14 %
Soltero sin hijos y con ingresos anuales de 100 000 euros
Impuesto = 22 986 euros
Descuento = 0 euros
Descuento = 0 euros
Tasa impositiva = 41 %
Impuesto = 22 986 euros
Recargo = 0 euros
Descuento = 0 euros
Reducción = 0 euros
Tasa impositiva = 41 %
Pareja con dos hijos y ingresos anuales de 30 000 euros
Impuesto = 0 euros
Descuento = 0 euros
Descuento = 0 euros
Tasa impositiva = 0 %
Impuesto = 0 euros
Descuento = 0 euros
Descuento = 0 euros
Tasa impositiva = 0 %
Soltero sin hijos y con ingresos anuales de 200 000 euros
Impuesto = 64 211 euros
Descuento = 0 euros
Descuento = 0 euros
Tasa impositiva = 45 %
Impuesto = 64 210 euros
Recargo = 7498 euros
descuento = 0 euros
Reducción = 0 euros
Tasa impositiva = 45 %
Pareja con 3 hijos y ingresos anuales de 200 000 euros
Impuesto = 42 843 euros
Descuento = 0 euros
Descuento = 0 euros
Tasa impositiva = 41 %
Impuesto = 42 842 euros
Recargo = 17 283 euros
descuento = 0 euros
Reducción = 0 euros
Tasa impositiva = 41 %

En el ejemplo anterior, se denomina recargo a lo que pagan de más las personas con ingresos altos debido a dos fenómenos:

  • el límite máximo de la deducción del 10 % sobre los ingresos anuales;
  • el límite máximo del coeficiente familiar;

Este indicador no se pudo verificar porque el simulador de la administración tributaria no lo proporciona.

Se observa que el algoritmo del documento calcula el impuesto correcto en todos los casos, aunque con un margen de error de 1 euro. Este margen de error se debe a los redondeos. Todas las cantidades monetarias se redondean a veces al euro superior y otras al euro inferior. Como no conocía las reglas oficiales, las cantidades del algoritmo del documento se redondearon:

  • al euro superior para los descuentos y rebajas;
  • al euro inferior para los recargos y el impuesto final;

Vamos a desarrollar varias versiones de la aplicación para calcular el impuesto.

8.2. Versión 1

Image

8.2.1. El script principal

Presentamos un primer programa en el que:

  • los datos necesarios para el cálculo del impuesto están codificados de forma fija en el código en forma de listas y constantes;
  • los datos de los contribuyentes (estado civil, hijos, salario) se encuentran en un primer archivo de texto [taxpayersdata.txt];
  • los resultados del cálculo del impuesto (estado civil, hijos, salario, impuesto) se almacenan en un segundo archivo de texto [résultats.txt];

El script [v-01/main.py] es el siguiente:


# módulos
import sys

from impots.v01.shared.impôts_module_01 import *

# main -----------------------

# constantes
# archivo de contribuyentes
DATA = "./data/taxpayersdata.txt"
# archivo de resultados
RESULTATS = "./data/résultats.txt"

try:
    # lectura de los datos de los contribuyentes
    tax_payers = get_taxpayers_data(DATA)
    # lista de resultados
    results = []
    # se calcula el impuesto de los contribuyentes
    for tax_payer in tax_payers:
        # el cálculo del impuesto devuelve un diccionario de claves
        # ['marié', 'enfants', 'salaire', 'impôt', 'surcôte', 'décôte', 'réduction', 'taux']
        result = calcul_impôt(tax_payer['marié'], tax_payer['enfants'], tax_payer['salaire'])
        # el diccionario se agrega a la lista de resultados
        results.append(result)
    # se guardan los resultados
    record_results(RESULTATS, results)
except BaseException as erreur:
    # pueden presentarse diferentes errores: falta el archivo, contenido incorrecto del archivo
    # se muestra el error y se sale de la aplicación
    print(f"l'erreur suivante s'est produite : {erreur}]\n")
    sys.exit()

Notas

  • línea 4: se utiliza el módulo [impots.v01.modules.impôts_module_01]. Cabe recordar que esta ruta se mide a partir de la raíz del proyecto PyCharm;
  • línea 10: el archivo [data/taxpayersdata.txt] es el siguiente:
oui,2,55555
oui,2,50000
oui,3,50000
non,2,100000
non,3,100000
oui,3,100000
oui,5,100000
non,0,100000
oui,2,30000
non,0,200000
oui,3,200000

Cada línea representa una tupla de tres elementos [marié / pacsé ou pas, nombre d'enfants, salaire annuel en euros].

  • línea 12: el archivo donde se colocarán los resultados del cálculo del impuesto para cada uno de los contribuyentes del archivo [taxpayersdata.txt]. Tendrá el siguiente contenido:
{'marié': 'oui', 'enfants': 2, 'salaire': 55555, 'impôt': 2814, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.14}
{'marié': 'oui', 'enfants': 2, 'salaire': 50000, 'impôt': 1384, 'surcôte': 0, 'décôte': 384, 'réduction': 347, 'taux': 0.14}
{'marié': 'oui', 'enfants': 3, 'salaire': 50000, 'impôt': 0, 'surcôte': 0, 'décôte': 720, 'réduction': 0, 'taux': 0.14}
{'marié': 'non', 'enfants': 2, 'salaire': 100000, 'impôt': 19884, 'surcôte': 4480, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'non', 'enfants': 3, 'salaire': 100000, 'impôt': 16782, 'surcôte': 7176, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'oui', 'enfants': 3, 'salaire': 100000, 'impôt': 9200, 'surcôte': 2180, 'décôte': 0, 'réduction': 0, 'taux': 0.3}
{'marié': 'oui', 'enfants': 5, 'salaire': 100000, 'impôt': 4230, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.14}
{'marié': 'non', 'enfants': 0, 'salaire': 100000, 'impôt': 22986, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'oui', 'enfants': 2, 'salaire': 30000, 'impôt': 0, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0}
{'marié': 'non', 'enfants': 0, 'salaire': 200000, 'impôt': 64210, 'surcôte': 7498, 'décôte': 0, 'réduction': 0, 'taux': 0.45}
{'marié': 'oui', 'enfants': 3, 'salaire': 200000, 'impôt': 42842, 'surcôte': 17283, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
  • línea 16: se recuperan los datos de los contribuyentes contenidos en [taxpayersdata.txt]. Se recupera una lista de diccionarios de claves [marié, enfants, salaire], donde cada diccionario representa a un contribuyente;
  • líneas 17-25: se calcula el impuesto de los contribuyentes de la lista [taxPayers]. Se recupera una lista [results], en la que cada elemento es, a su vez, un diccionario de claves [marié, enfants, salaire, impôt, surcôte, décôte, réduction, taux];
  • línea 27: la lista [results] de resultados se guarda en el archivo [résultats.txt] en el formato mostrado anteriormente;
  • líneas 28-32: se interceptan todas las excepciones que puedan surgir del módulo [impots.v01.modules.impôts_module_01];

Ahora vamos a detallar las tres funciones que utiliza el script [main]:

  • [get_taxpayers_data]: para leer los datos de los contribuyentes;
  • [calcul_impôt]: para calcular el impuesto de estos;
  • [record_results]: para guardar los resultados en un archivo de texto;

Todas estas funciones se encuentran en el módulo [impots.modules.impôts_module_01].

8.2.2. El módulo [impots.v01.shared.impôts_module_01]

Las funciones necesarias para el cálculo del impuesto se han reunido en el módulo [impots.v01.shared.impôts_module_01]:

Image

  • en [1]: definición de las constantes para el cálculo del impuesto;
  • en [2]: la lista de funciones del módulo;

8.2.3. La función [get_taxpayers_data]

La función [get_taxpayers_data] es la siguiente:


# importaciones
import codecs


# lectura de los datos de los contribuyentes
# ----------------------------------------
def get_taxpayers_data(taxpayers_filename: str) -> list:
    # lectura de los datos de los contribuyentes
    file = None
    try:
        # la lista de contribuyentes
        taxpayers = []
        # apertura del archivo
        file = codecs.open(taxpayers_filename, "r", "utf8")
        # se lee la primera línea del archivo de contribuyentes
        ligne = file.readline().strip()
        # mientras quede una línea por procesar
        while ligne != '':
            # se recuperan los tres campos «casado», «hijos» y «salario» que conforman la línea
            (marié, enfants, salaire) = ligne.split(",")
            # se agregan a la lista de contribuyentes
            taxpayers.append({'marié': marié.strip().lower(), 'enfants': int(enfants), 'salaire': int(salaire)})
            # se lee una nueva línea del archivo de contribuyentes
            ligne = file.readline().strip()
        # se devuelve el resultado
        return taxpayers
    finally:
        # se cierra el archivo si estaba abierto
        if file:
            file.close()

Notas

  • línea 7: [taxpayers_filename] es el nombre del archivo que se va a procesar. La función devuelve una lista;
  • líneas 18-24: el bucle de procesamiento de las líneas [marié, enfants, salaire] del archivo de texto;
  • línea 20: se recuperan los tres elementos de la línea. Aquí se supone que la línea es sintácticamente correcta, es decir, que cuenta con los tres elementos esperados;
  • línea 22: se construye un diccionario con las claves [marié, enfants, salaire] y este diccionario se agrega a la lista [taxPayers];
  • línea 26: una vez procesado el archivo, se devuelve la lista [taxPayers];
  • líneas 10-30: cabe señalar que no se ha incluido la cláusula [catch] en [try] de la línea 10. La cláusula [catch] no es obligatoria. En la línea 27, se ha incluido una cláusula [finally] para cerrar el archivo de texto en cualquier caso, haya error o no;
  • esta estructura try / finally permite que se escape una posible excepción (no hay un catch). Esta excepción se propagará al script principal [main], el cual se detendrá y mostrará la excepción (véase el párrafo |El script principal|). Este mecanismo se ha utilizado para la mayoría de las funciones del módulo;

8.2.4. La función [calcul_impôt]

La función [calcul_impôt] es la siguiente:


# importaciones
import codecs
import math

# tramos del impuesto de 2019
limites = [9964, 27519, 73779, 156244, 0]
coeffr = [0, 0.14, 0.3, 0.41, 0.45]
coeffn = [0, 1394.96, 5798, 13913.69, 20163.45]

# constantes para el cálculo del impuesto de 2019
PLAFOND_QF_DEMI_PART = 1551
PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION = 21037
PLAFOND_REVENUS_COUPLE_POUR_REDUCTION = 42074
VALEUR_REDUC_DEMI_PART = 3797
PLAFOND_DECOTE_CELIBATAIRE = 1196
PLAFOND_DECOTE_COUPLE = 1970
PLAFOND_IMPOT_COUPLE_POUR_DECOTE = 2627
PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE = 1595
ABATTEMENT_DIXPOURCENT_MAX = 12502
ABATTEMENT_DIXPOURCENT_MIN = 437


# cálculo del impuesto
# ----------------------------------------
def calcul_impôt(marié: str, enfants: int, salaire: int) -> dict:
    # casado: sí, no
    # hijos: número de hijos
    # salario: salario anual
    # límites, coeffr, coeffn: las tablas de datos que permiten el cálculo del impuesto
    #
    # cálculo del impuesto con hijos
    result1 = calcul_impôt_2(marié, enfants, salaire)
    impot1 = result1["impôt"]
    # cálculo del impuesto sin hijos
    if enfants != 0:
        result2 = calcul_impôt_2(marié, 0, salaire)
        impot2 = result2["impôt"]
        # Aplicación del límite máximo del coeficiente familiar
        if enfants < 3:
            # PLAFOND_QF_DEMI_PART euros para los dos primeros hijos
            impot2 = impot2 - enfants * PLAFOND_QF_DEMI_PART
        else:
            # PLAFOND_QF_DEMI_PART euros para los dos primeros hijos, el doble para los siguientes
            impot2 = impot2 - 2 * PLAFOND_QF_DEMI_PART - (enfants - 2) * 2 * PLAFOND_QF_DEMI_PART
    else:
        impot2 = impot1
        result2 = result1

    # se toma el impuesto más alto con la tasa y el recargo correspondientes
    if impot1 > impot2:
        impot = impot1
        taux = result1["taux"]
        surcôte = result1["surcôte"]
    else:
        surcôte = impot2 - impot1 + result2["surcôte"]
        impot = impot2
        taux = result2["taux"]

    # cálculo de una posible reducción
    décôte = get_décôte(marié, salaire, impot)
    impot -= décôte
    # cálculo de una posible reducción de impuestos
    réduction = get_réduction(marié, salaire, enfants, impot)
    impot -= réduction
    # resultado
    return {"marié": marié, "enfants": enfants, "salaire": salaire, "impôt": math.floor(impot), "surcôte": surcôte,
            "décôte": décôte, "réduction": réduction, "taux": taux}

Notas

  • líneas 6-8: los tramos del impuesto (véase el párrafo |Cálculo del impuesto bruto|);
  • líneas 11-20: las constantes del cálculo del impuesto;
  • Cabe señalar que los elementos inicializados en las líneas 5 a 20 serán globales para las funciones que vamos a describir. Por lo tanto, se conocen siempre y cuando la función que los utilice no declare variables con los mismos nombres;
  • las cifras de las líneas 5-20 cambian cada año. Aquí se trata de las cifras de 2019;
  • línea 25: la función [calcul_impôt] recibe tres parámetros:
    • [marié]: sí / no, indica si el contribuyente está casado o en unión civil;
    • [enfants]: su número de hijos;
    • [salaire]: su salario anual en euros;
  • líneas 31-33: cálculo del impuesto teniendo en cuenta los hijos;
  • líneas 34-47: estas líneas aplican el límite máximo del coeficiente familiar (véase el párrafo |Límite máximo del coeficiente familiar|);
  • líneas 49-57: estas líneas calculan la tasa impositiva del contribuyente, así como un posible recargo (véase el párrafo |Casos de ingresos elevados|);
  • líneas 59-61: cálculo de una posible reducción (véase el párrafo |Cálculo de la reducción|);
  • líneas 62-64: cálculo de una posible reducción del impuesto a pagar (véase el párrafo |Cálculo de la reducción de impuestos|);

El algoritmo es bastante complejo y no lo detallaremos más allá de lo que indican los comentarios. El algoritmo implementa el método de cálculo del impuesto tal como se describe en el párrafo |El problema|.

8.2.5. La función [calcul_impôt_2]

La función [calcul_impôt] utiliza la siguiente función [calcul_impôt_2]:


def calcul_impôt_2(marié: str, enfants: int, salaire: int) -> list:
    # casado: sí, no
    # hijos: número de hijos
    # salario: salario anual
    # límites, coeffr, coeffn: las tablas de datos que permiten calcular el impuesto
    #
    # número de partes
    marié = marié.strip().lower()
    if marié == "oui":
        nb_parts = enfants / 2 + 2
    else:
        nb_parts = enfants / 2 + 1

    # 1 parte por hijo a partir del tercero
    if enfants >= 3:
        # media parte adicional por cada hijo a partir del tercero
        nb_parts += 0.5 * (enfants - 2)

    # ingresos imponibles
    revenu_imposable = get_revenu_imposable(salaire)
    # recargo
    surcôte = math.floor(revenu_imposable - 0.9 * salaire)
    # por problemas de redondeo
    if surcôte < 0:
        surcôte = 0

    # coeficiente familiar
    quotient = revenu_imposable / nb_parts
    # se coloca al final de la tabla de límites para detener el bucle que sigue
    limites[len(limites) - 1] = quotient
    # cálculo del impuesto
    i = 0
    while quotient > limites[i]:
        i += 1
        # debido a que se colocó el cociente familiar al final de la tabla de límites, el bucle anterior
    # no puede sobrepasar los límites de la tabla

    # ahora se puede calcular el impuesto
    impôt = math.floor(revenu_imposable * coeffr[i] - nb_parts * coeffn[i])
    # resultado
    return {"impôt": impôt, "surcôte": surcôte, "taux": coeffr[i]}

Este algoritmo se describió en el párrafo 8.1.1.

8.2.6. La función [get_décôte]

La función [get_décôte] implementa el cálculo de la posible reducción del impuesto (apartado |Cálculo de la reducción|):


# calcula una posible reducción
def get_décôte(marié: str, salaire: int, impots: int) -> int:
    # Inicialmente, un descuento nulo
    décôte = 0
    # monto máximo del impuesto para tener derecho al descuento
    plafond_impôt_pour_décôte = PLAFOND_IMPOT_COUPLE_POUR_DECOTE if marié == "oui" else PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE
    if impots < plafond_impôt_pour_décôte:
        # monto máximo de la reducción
        plafond_décôte = PLAFOND_DECOTE_COUPLE if marié == "oui" else PLAFOND_DECOTE_CELIBATAIRE
        # descuento teórico
        décôte = plafond_décôte - 0.75 * impots
        # la deducción no puede superar el monto del impuesto
        if décôte > impots:
            décôte = impots

        # no hay descuento <0
        if décôte < 0:
            décôte = 0

    # resultado
    return math.ceil(décôte)

8.2.7. La función [get_réduction]

La función [get_réduction] implementa el cálculo de la posible reducción del impuesto a pagar (párrafo |Cálculo de la reducción de impuestos|):


# calcula una posible reducción
def get_réduction(marié: str, salaire: int, enfants: int, impots: int) -> int:
    # el límite máximo de ingresos para tener derecho a la reducción del 20 %
    plafond_revenu_pour_réduction = PLAFOND_REVENUS_COUPLE_POUR_REDUCTION if marié == "oui" else PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION
    plafond_revenu_pour_réduction += enfants * VALEUR_REDUC_DEMI_PART
    if enfants > 2:
        plafond_revenu_pour_réduction += (enfants - 2) * VALEUR_REDUC_DEMI_PART

    # ingresos imponibles
    revenu_imposable = get_revenu_imposable(salaire)
    # descuento
    réduction = 0
    if revenu_imposable < plafond_revenu_pour_réduction:
        # reducción del 20 %
        réduction = 0.2 * impots

    # resultado
    return math.ceil(réduction)

8.2.8. La función [get_revenu_imposable]

La función [get_revenu_imposable] calcula el ingreso imponible a partir del salario anual:


# revenu_imposable = salaireAnnuel - deducción
# la deducción tiene un mínimo y un máximo
# ----------------------------------------
def get_revenu_imposable(salaire: int) -> int:
    # descuento del 10 % del salario
    abattement = 0.1 * salaire
    # esta deducción no puede superar ABATTEMENT_DIXPOURCENT_MAX
    if abattement > ABATTEMENT_DIXPOURCENT_MAX:
        abattement = ABATTEMENT_DIXPOURCENT_MAX

    # la deducción no puede ser inferior a ABATTEMENT_DIXPOURCENT_MIN
    if abattement < ABATTEMENT_DIXPOURCENT_MIN:
        abattement = ABATTEMENT_DIXPOURCENT_MIN

    # ingresos imponibles
    revenu_imposable = salaire - abattement
    # resultado
    return math.floor(revenu_imposable)

8.2.9. La función [record_results]

La función [record_results] guarda los resultados del cálculo del impuesto en un archivo de texto:


# escritura de los resultados en un archivo de texto
# ----------------------------------------
def record_results(results_filename: str, results: list):
    # results_filename: el nombre del archivo de texto donde se guardarán los resultados
    # results: la lista de resultados en forma de una lista de diccionarios
    # cada diccionario se escribe en una línea de texto
    résultats = None
    try:
        # apertura del archivo de resultados
        résultats = codecs.open(results_filename, "w", "utf8")
        # procesamiento de los contribuyentes
        for result in results:
            # se registra el resultado en el archivo de resultados
            résultats.write(f"{result}\n")
            # siguiente contribuyente
    finally:
        # se cierra el archivo si se ha abierto
        if résultats:
            résultats.close()

8.2.10. Los resultados

Como ya se mencionó, con el siguiente archivo de contribuyentes [taxpayersdata.txt]:

oui,2,55555
oui,2,50000
oui,3,50000
non,2,100000
non,3,100000
oui,3,100000
oui,5,100000
non,0,100000
oui,2,30000
non,0,200000
oui,3,200000

el script [main.py] crea el siguiente archivo [résultats.txt]:

{'marié': 'oui', 'enfants': 2, 'salaire': 55555, 'impôt': 2814, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.14}
{'marié': 'oui', 'enfants': 2, 'salaire': 50000, 'impôt': 1384, 'surcôte': 0, 'décôte': 384, 'réduction': 347, 'taux': 0.14}
{'marié': 'oui', 'enfants': 3, 'salaire': 50000, 'impôt': 0, 'surcôte': 0, 'décôte': 720, 'réduction': 0, 'taux': 0.14}
{'marié': 'non', 'enfants': 2, 'salaire': 100000, 'impôt': 19884, 'surcôte': 4480, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'non', 'enfants': 3, 'salaire': 100000, 'impôt': 16782, 'surcôte': 7176, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'oui', 'enfants': 3, 'salaire': 100000, 'impôt': 9200, 'surcôte': 2180, 'décôte': 0, 'réduction': 0, 'taux': 0.3}
{'marié': 'oui', 'enfants': 5, 'salaire': 100000, 'impôt': 4230, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.14}
{'marié': 'non', 'enfants': 0, 'salaire': 100000, 'impôt': 22986, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'oui', 'enfants': 2, 'salaire': 30000, 'impôt': 0, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0}
{'marié': 'non', 'enfants': 0, 'salaire': 200000, 'impôt': 64210, 'surcôte': 7498, 'décôte': 0, 'réduction': 0, 'taux': 0.45}
{'marié': 'oui', 'enfants': 3, 'salaire': 200000, 'impôt': 42842, 'surcôte': 17283, 'décôte': 0, 'réduction': 0, 'taux': 0.41}

Estos resultados coinciden con las cifras oficiales del apartado |Cifras oficiales|.

Ahora, ejecutemos esta versión en una ventana de consola:


(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\impots\v01>python main.py
Traceback (most recent call last):
  File "main.py", line 4, in <module>
    from impots.v01.shared.impôts_module_01 import *
ModuleNotFoundError: No module named 'impots'

Vuelve a aparecer un error que ya hemos visto antes: el de que no se encuentra un módulo, en este caso el módulo [impots]. Recordemos que esto significa que:

  • el intérprete de Python ha recorrido una por una las carpetas de la ruta de Python;
  • en ninguna de ellas encontró una carpeta que contuviera un script [impots.py];

La versión [v02] resolverá este problema.