Skip to content

8. Ćwiczenie praktyczne – wersja 1

8.1. Problem

Image

Powyższa tabela pozwala obliczyć podatek w uproszczonym przypadku podatnika, który zgłasza wyłącznie swoje wynagrodzenie. Jak wskazuje uwaga (1), tak obliczony podatek jest podatkiem przed zastosowaniem trzech mechanizmów:

  • ograniczenia współczynnika rodzinnego, które ma zastosowanie w przypadku wysokich dochodów;
  • ulgi i obniżki podatkowe, które mają zastosowanie w przypadku niskich dochodów;

W związku z tym obliczenie podatku obejmuje następujące etapy [http://impotsurlerevenu.org/comprendre-le-calcul-de-l-impot/1217-calcul-de-l-impot-2019.php]:

Image

Proponujemy napisanie programu umożliwiającego obliczenie podatku podatnika w uproszczonym przypadku, gdy podatnik ma do zadeklarowania wyłącznie swoje wynagrodzenie:

8.1.1. Obliczanie podatku brutto

Podatek brutto można obliczyć w następujący sposób:

Najpierw oblicza się liczbę udziałów podatnika:

  • każdy z rodziców wnosi 1 część;
  • dwoje pierwszych dzieci wnosi po 1/2 części;
  • kolejne dzieci wnoszą po jednej części:

Liczba udziałów wynosi zatem:

  • nbParts=1+nbEnfants*0,5+(liczbaDzieci-2)*0,5, jeśli pracownik nie jest żonaty;
  • nbParts = 2 + nbEnfants * 0,5 + (nbEnfants – 2) * 0,5, jeśli jest żonaty;
    • gdzie nbEnfants oznacza liczbę dzieci;
  • oblicza się dochód podlegający opodatkowaniu R = 0,9 * S, gdzie S to roczne wynagrodzenie;
  • oblicza się współczynnik rodzinny QF = R / nbParts;
  • oblicza się podatek brutto I na podstawie następujących danych (2019):
9964
0
0
27519
0,14
1394,96
73779
0,3
5798
156 244
0,4
13913,69
0
0,45
20163,45

Każdy wiersz zawiera 3 pola: champ1, champ2, champ3. Aby obliczyć podatek I, szukamy pierwszego wiersza, w którym QF ≤ pole1, i pobieramy wartości z tego wiersza. Na przykład dla pracownika pozostającego w związku małżeńskim, mającego dwoje dzieci i roczne wynagrodzenie S w wysokości 50 000 euro:

Dochód podlegający opodatkowaniu: R = 0,9 * S = 45 000

Liczba udziałów: nbParts = 2 + 2 * 0,5 = 3

Współczynnik rodzinny: QF = 45 000 / 3 = 15 000

Pierwszy wiersz, w którym QF <= pole1, wygląda następująco:

    27519    0.14    1394.96

Podatek I wynosi zatem 0,14*R – 1394,96*nbParts=[0,14*45000-1394,96*3]=2115. Podatek jest zaokrąglany w dół do najbliższego euro.

Jeśli już w pierwszym wierszu zachodzi relacja QF ≤ pole1, wówczas podatek wynosi zero.

Jeśli QF jest takie, że warunek QF <= pole1 nigdy nie jest spełniony, wówczas stosuje się współczynniki z ostatniego wiersza. W tym przypadku:

    0    0.45    20163.45

co daje podatek brutto I = 0,45*R – 20163,45*nbParts.

8.1.2. Ograniczenie ilorazu rodzinnego

Image

Aby sprawdzić, czy ma zastosowanie limit ilorazu rodzinnego QF, ponownie obliczamy podatek brutto bez uwzględnienia dzieci. Nadal dla pracownika pozostającego w związku małżeńskim, mającego dwoje dzieci i roczne wynagrodzenie S w wysokości 50 000 euro:

Dochód podlegający opodatkowaniu: R = 0,9 * S = 45 000

Liczba udziałów: nbParts=2 (nie uwzględnia się już dzieci)

Współczynnik rodzinny: QF = 45 000 / 2 = 22 500

Pierwszy wiersz, w którym QF <= pole1, wygląda następująco:

    27519    0.14    1394.96

Podatek I wynosi zatem 0,14*R – 1394,96*nbParts = [0,14*45000-1394,96*2] = 3510.

Maksymalna ulga na dzieci: 1551 * 2 = 3102 euro

Podatek minimalny: 3510 – 3102 = 408 euro

Podatek brutto z uwzględnieniem 3 udziałów, wynoszący 2115 euro, jest wyższy od podatku minimalnego wynoszącego 408 euro, dlatego w tym przypadku nie ma zastosowania limit rodzinny.

Ogólnie rzecz biorąc, podatek brutto jest większy niż (podatek1, podatek2), gdzie:

  • [impôt1]: to podatek brutto obliczony z uwzględnieniem dzieci;
  • [impôt2]: to podatek brutto obliczony bez uwzględnienia dzieci i pomniejszony o maksymalną ulgę (w tym przypadku 1551 euro na pół części) związaną z dziećmi;

8.1.3. Obliczanie ulgi

Image

Wciąż w przypadku pracownika pozostającego w związku małżeńskim, mającego dwoje dzieci i roczne wynagrodzenie S w wysokości 50 000 euro:

Podatek brutto (2115) uzyskany w poprzednim etapie jest niższy niż 2627 euro dla pary (1595 euro dla osoby samotnej): w związku z tym ma zastosowanie ulga. Oblicza się ją w następujący sposób:

obniżka = próg (para = 1970 / osoba samotna = 1196) – 0,75 * podatek brutto

obniżka = 1970 – 0,75 * 2115 = 383,75, zaokrąglone do 384 euro.

Nowy podatek brutto = 2115 – 384 = 1731 euro

8.1.4. Obliczenie ulgi podatkowej

Image

Poniżej określonego progu od podatku brutto wynikającego z powyższych obliczeń przyznaje się ulgę w wysokości 20%. W 2019 r. progi te wynoszą:

  • osoba samotna: 21 037 euro;
  • para: 42 074 euro; (liczba 37 968 podana w powyższym przykładzie wydaje się błędna);

Próg ten zwiększa się o wartość: 3797 * (liczba pół-udziałów wnoszonych przez dzieci).

W przypadku pracownika pozostającego w związku małżeńskim, mającego dwoje dzieci i roczne wynagrodzenie S w wysokości 50 000 euro:

  • jego dochód podlegający opodatkowaniu (45 000 euro) jest niższy od progu (42 074 + 2 × 3797) = 49 668 euro;
  • ma zatem prawo do 20-procentowej ulgi podatkowej: 1731 * 0,2 = 346,2 euro, zaokrąglone do 347 euro;
  • podatek brutto podatnika wynosi: 1731 – 347 = 1384 euro;

8.1.5. Obliczenie podatku netto

Na tym zakończymy nasze obliczenia: podatek netto do zapłaty wyniesie 1384 euro. W rzeczywistości podatnik może skorzystać z innych ulg, w szczególności z tytułu darowizn na rzecz organizacji pożytku publicznego lub ogólnego.

8.1.6. Przypadek wysokich dochodów

Nasz poprzedni przykład dotyczy większości pracowników najemnych. Jednak w przypadku wysokich dochodów obliczenie podatku przebiega inaczej.

8.1.6.1. Ograniczenie 10-procentowej ulgi od rocznych dochodów

W większości przypadków dochód podlegający opodatkowaniu oblicza się według wzoru: R = 0,9 * S, gdzie S oznacza roczne wynagrodzenie. Nazywa się to 10-procentową ulgą. Ulga ta podlega ograniczeniu. W 2019 r.:

  • nie może przekraczać 12 502 euro;
  • nie może być niższa niż 437 euro;

Weźmy na przykład pracownika niebędącego w związku małżeńskim, bezdzietnego, o rocznym wynagrodzeniu w wysokości 200 000 euro:

  • 10-procentowa redukcja wynosi 200 000 euro > 12 502 euro. Zostaje zatem ograniczona do 12 502 euro;

8.1.6.2. Ograniczenie ilorazu rodzinnego

Rozważmy przypadek, w którym ma zastosowanie limit rodzinny przedstawiony w paragrafie |Plafonnement du quotient familial|. Weźmy pod uwagę parę z trójką dzieci i rocznym dochodem w wysokości 100 000 euro. Przeanalizujmy kolejne etapy obliczeń:

  • odliczenie w wysokości 10% wynosi 10 000 euro < 12 502 euro. Dochód podlegający opodatkowaniu R wynosi zatem 100 000 – 10 000 = 90 000 euro;
  • para posiada nbParts = 2 + 0,5 × 2 + 1 = 4 części;
  • jej współczynnik rodzinny wynosi zatem QF = R / nbParts = 90 000 / 4 = 22 500 euro;
  • ich podatek brutto I1 z uwzględnieniem dzieci wynosi I1=0,14*90 000 - 1 394,96*4 = 7 020 euro;
  • jego podatek brutto I2 bez dzieci:
  • QF = 90 000 / 2 = 45 000 euro;
  • I2 = 0,3 × 90 000 – 5 798 × 2 = 15 404 euro;
  • zasada ograniczenia ilorazu rodzinnego stanowi, że korzyść wynikająca z posiadania dzieci nie może przekroczyć (1551 × 4 półczęści) = 6204 euro. W tym przypadku wynosi ona jednak I2-I1 = 15404 – 7020 = 8384 euro, a więc jest wyższa niż 6204 euro;
  • podatek brutto jest zatem przeliczany jako I3 = I2-6204 = 15 404 – 6 204 = 9 200 euro;

Para ta nie otrzyma ani ulgi, ani obniżki, a jej ostateczny podatek wyniesie 9200 euro.

8.1.7. Oficjalne dane

Obliczanie podatku jest skomplikowane. W całym dokumencie testy będą przeprowadzane na podstawie poniższych przykładów. Wyniki pochodzą z symulatora urzędu skarbowego |https://www3.impots.gouv.fr/simulateur/calcul_impot/2019/simplifie/index.htm|:

Podatnik
Oficjalne wyniki
Wyniki algorytmu przedstawionego w dokumencie
Para z dwójką dzieci i rocznym dochodem w wysokości 55 555 euro
Podatek = 2815 euro
Stawka podatkowa = 14 %
Podatek = 2814 euro
Stawka podatkowa = 14 %
Para z dwójką dzieci i rocznym dochodem w wysokości 50 000 euro
Podatek = 1385 euro
Ulga = 720 euro
Ulga = 0 euro
Stawka podatkowa = 14 %
Podatek = 1384 euro
Odliczenie = 384 euro
Ulga = 347 euro
Stawka podatkowa = 14 %
Para z trójką dzieci i rocznym dochodem w wysokości 50 000 euro
Podatek = 0 euro
ulga = 384 euro
Ulga = 346 euro
Stawka podatkowa = 14 %
Podatek = 0 euro
odliczenie = 720 euro
Ulga = 0 euro
Stawka podatkowa = 14 %
Osoba samotna z dwójką dzieci i rocznym dochodem w wysokości 100 000 euro
Podatek = 19 884 euro
ulga = 0 euro
Ulga = 0 euro
Stawka podatkowa = 41 %
Podatek = 19 884 euro
Dodatek = 4480 euro
obniżka = 0 euro
Ulga = 0 euro
Stawka podatkowa = 41 %
Osoba samotna z trójką dzieci i rocznym dochodem w wysokości 100 000 euro
Podatek = 16 782 euro
ulga = 0 euro
Ulga = 0 euro
Stawka podatkowa = 41 %
Podatek = 16 782 euro
Dodatek = 7176 euro
obniżka = 0 euro
Ulga = 0 euro
Stawka podatkowa = 41 %
Para z trójką dzieci i rocznym dochodem w wysokości 100 000 euro
Podatek = 9200 euro
ulga = 0 euro
Ulga = 0 euro
Stawka podatkowa = 30 %
Podatek = 9200 euro
Dodatek = 2180 euro
obniżka = 0 euro
Ulga = 0 euro
Stawka podatkowa = 30 %
Para z pięciorgiem dzieci i rocznym dochodem w wysokości 100 000 euro
Podatek = 4230 euro
ulga = 0 euro
Ulga = 0 euro
Stawka podatkowa = 14 %
Podatek = 4230 euro
ulga = 0 euro
Ulga = 0 euro
Stawka podatkowa = 14 %
Osoba samotna bez dzieci, z rocznym dochodem w wysokości 100 000 euro
Podatek = 22 986 euro
ulga = 0 euro
Ulga = 0 euro
Stawka podatkowa = 41 %
Podatek = 22 986 euro
Dodatek = 0 euro
obniżka = 0 euro
Ulga = 0 euro
Stawka podatkowa = 41 %
Para z dwójką dzieci i rocznym dochodem w wysokości 30 000 euro
Podatek = 0 euro
ulga = 0 euro
Ulga = 0 euro
Stawka podatkowa = 0 %
Podatek = 0 euro
odliczenie = 0 euro
Ulga = 0 euro
Stawka podatkowa = 0 %
Osoba samotna bez dzieci, z rocznym dochodem w wysokości 200 000 euro
Podatek = 64 211 euro
ulga = 0 euro
Ulga = 0 euro
Stawka podatkowa = 45 %
Podatek = 64 210 euro
Dopłata = 7498 euro
obniżka = 0 euro
Ulga = 0 euro
Stawka podatkowa = 45 %
Para z trójką dzieci i rocznym dochodem w wysokości 200 000 euro
Podatek = 42 843 euro
ulga = 0 euro
Ulga = 0 euro
Stawka podatkowa = 41 %
Podatek = 42 842 euro
Dodatek = 17 283 euro
obniżka = 0 euro
Ulga = 0 euro
Stawka podatkowa = 41 %

W powyższym przykładzie jako dopłatę określa się kwotę, którą osoby o wysokich dochodach płacą dodatkowo z powodu dwóch czynników:

  • ograniczenie ulgi podatkowej do 10% rocznego dochodu;
  • ograniczenie współczynnika rodzinnego;

Wskaźnika tego nie udało się zweryfikować, ponieważ symulator urzędu skarbowego go nie podaje.

Widać, że algorytm zawarty w dokumencie za każdym razem podaje prawidłową kwotę podatku, jednak z marginesem błędu wynoszącym 1 euro. Margines ten wynika z zaokrągleń. Wszystkie kwoty są czasami zaokrąglane w górę do pełnego euro, a czasami w dół do pełnego euro. Ponieważ nie znałem oficjalnych zasad, kwoty w algorytmie zawartym w dokumencie zostały zaokrąglone:

  • w górę do pełnego euro w przypadku zniżek i ulg;
  • w dół do pełnego euro w przypadku dopłat i podatku końcowego;

Opracujemy kilka wersji aplikacji do obliczania podatku.

8.2. Wersja 1

Image

8.2.1. Skrypt główny

Przedstawiamy pierwszy program, w którym:

  • dane niezbędne do obliczenia podatku są na stałe zapisane w kodzie w postaci list i stałych;
  • dane podatników (stan cywilny, dzieci, wynagrodzenie) znajdują się w pierwszym pliku tekstowym [taxpayersdata.txt];
  • wyniki obliczeń podatku (stan cywilny, dzieci, wynagrodzenie, podatek) są zapisywane w drugim pliku tekstowym [résultats.txt];

Skrypt [v-01/main.py] wygląda następująco:


# moduły
import sys

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

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

# stałe
# plik podatników
DATA = "./data/taxpayersdata.txt"
# plik wyników
RESULTATS = "./data/résultats.txt"

try:
    # odczyt danych podatników
    tax_payers = get_taxpayers_data(DATA)
    # lista wyników
    results = []
    # obliczanie podatku podatników
    for tax_payer in tax_payers:
        # obliczenie podatku zwraca słownik kluczy
        # ['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'])
        # słownik został dodany do listy wyników
        results.append(result)
    # zapisano wyniki
    record_results(RESULTATS, results)
except BaseException as erreur:
    # mogą wystąpić różne błędy: brak pliku, nieprawidłowa zawartość pliku
    # wyświetlany jest komunikat o błędzie i aplikacja zostaje zamknięta
    print(f"l'erreur suivante s'est produite : {erreur}]\n")
    sys.exit()

Uwagi

  • wiersz 4: wykorzystuje się moduł [impots.v01.modules.impôts_module_01]. Przypominamy, że ścieżka ta jest mierzona od katalogu głównego projektu PyCharm;
  • wiersz 10: plik [data/taxpayersdata.txt] ma następującą treść:
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

Każdy wiersz reprezentuje krotkę składającą się z trzech elementów [marié / pacsé ou pas, nombre d'enfants, salaire annuel en euros].

  • wiersz 12: plik, w którym zostaną umieszczone wyniki obliczeń podatku dla każdego z podatników z pliku [taxpayersdata.txt]. Będzie on miał następującą zawartość:
{'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}
  • wiersz 16: pobierane są dane podatników zawarte w pliku [taxpayersdata.txt]. Pobierana jest lista słowników kluczy [marié, enfants, salaire], przy czym każdy słownik reprezentuje jednego podatnika;
  • wiersze 17–25: oblicza się podatek podatników z listy [taxPayers]. Pobierana jest lista [results], której każdy element jest z kolei słownikiem kluczy [marié, enfants, salaire, impôt, surcôte, décôte, réduction, taux];
  • wiersz 27: lista wyników [results] jest zapisywana w pliku [résultats.txt] w formie pokazanej powyżej;
  • wiersze 28–32: przechwytujemy wszystkie wyjątki, które mogą wystąpić w module [impots.v01.modules.impôts_module_01];

Omówimy teraz szczegółowo trzy funkcje wykorzystywane przez skrypt [main]:

  • [get_taxpayers_data]: do odczytu danych podatników;
  • [calcul_impôt]: do obliczania podatku tych podatników;
  • [record_results]: do zapisywania wyników w pliku tekstowym;

Wszystkie te funkcje znajdują się w module [impots.modules.impôts_module_01].

8.2.2. Moduł [impots.v01.shared.impôts_module_01]

Funkcje niezbędne do obliczenia podatku zostały zebrane w module [impots.v01.shared.impôts_module_01]:

Image

  • w [1]: definicja stałych służących do obliczania podatku;
  • w [2]: lista funkcji modułu;

8.2.3. Funkcja [get_taxpayers_data]

Funkcja [get_taxpayers_data] ma następującą postać:


# importy
import codecs


# odczyt danych podatników
# ----------------------------------------
def get_taxpayers_data(taxpayers_filename: str) -> list:
    # odczyt danych podatników
    file = None
    try:
        # lista podatników
        taxpayers = []
        # otwarcie pliku
        file = codecs.open(taxpayers_filename, "r", "utf8")
        # odczyt pierwszego wiersza pliku podatników
        ligne = file.readline().strip()
        # dopóki pozostał jeszcze wiersz do przetworzenia
        while ligne != '':
            # pobierane są 3 pola: „żonaty”, „dzieci” i „wynagrodzenie”, które tworzą ten wiersz
            (marié, enfants, salaire) = ligne.split(",")
            # dodaje się je do listy podatników
            taxpayers.append({'marié': marié.strip().lower(), 'enfants': int(enfants), 'salaire': int(salaire)})
            # odczytujemy nowy wiersz z pliku podatników
            ligne = file.readline().strip()
        # zwracamy wynik
        return taxpayers
    finally:
        # zamykamy plik, jeśli był otwarty
        if file:
            file.close()

Uwagi

  • wiersz 7: [taxpayers_filename] to nazwa pliku, który ma zostać przetworzony. Funkcja zwraca listę;
  • wiersze 18–24: pętla przetwarzająca wiersze o nazwie [marié, enfants, salaire] z pliku tekstowego;
  • wiersz 20: pobierane są trzy elementy wiersza. Zakłada się tutaj, że wiersz jest poprawny pod względem składniowym, tzn. zawiera trzy oczekiwane elementy;
  • wiersz 22: tworzony jest słownik z kluczami [marié, enfants, salaire], a słownik ten jest dodawany do listy [taxPayers];
  • wiersz 26: po przetworzeniu pliku zwracana jest lista [taxPayers];
  • wiersze 10–30: należy zauważyć, że nie dodano klauzuli [catch] do [try] z wiersza 10. Klauzula [catch] nie jest obowiązkowa. W wierszu 27 dodano klauzulę [finally], aby zamknąć plik tekstowy w każdym przypadku, niezależnie od tego, czy wystąpił błąd, czy nie;
  • ta struktura try / finally pozwala na wystąpienie ewentualnego wyjątku (brak instrukcji catch). Wyjątek ten zostanie przekazany do głównego skryptu [main], który zatrzyma się i wyświetli wyjątek (patrz akapit |Le script principal|). Mechanizm ten został zastosowany w większości funkcji modułu;

8.2.4. Funkcja [calcul_impôt]

Funkcja [calcul_impôt] wygląda następująco:


# importy
import codecs
import math

# progi podatkowe na rok 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]

# stałe do obliczenia podatku za rok 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


# obliczenie podatku
# ----------------------------------------
def calcul_impôt(marié: str, enfants: int, salaire: int) -> dict:
    # stan cywilny: tak, nie
    # dzieci: liczba dzieci
    # wynagrodzenie: roczne wynagrodzenie
    # limity, współczynnik, współczynnik n: tabele danych umożliwiające obliczenie podatku
    #
    # obliczenie podatku z uwzględnieniem dzieci
    result1 = calcul_impôt_2(marié, enfants, salaire)
    impot1 = result1["impôt"]
    # obliczenie podatku bez uwzględnienia dzieci
    if enfants != 0:
        result2 = calcul_impôt_2(marié, 0, salaire)
        impot2 = result2["impôt"]
        # zastosowanie limitu ilorazu rodzinnego
        if enfants < 3:
            # PLAFOND_QF_DEMI_PART euro na pierwsze dwoje dzieci
            impot2 = impot2 - enfants * PLAFOND_QF_DEMI_PART
        else:
            # PLAFOND_QF_DEMI_PART euro na pierwsze dwoje dzieci, dwukrotność tej kwoty na kolejne
            impot2 = impot2 - 2 * PLAFOND_QF_DEMI_PART - (enfants - 2) * 2 * PLAFOND_QF_DEMI_PART
    else:
        impot2 = impot1
        result2 = result1

    # bierzemy najwyższy podatek wraz z odpowiednią stawką i dopłatą
    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"]

    # obliczenie ewentualnej ulgi
    décôte = get_décôte(marié, salaire, impot)
    impot -= décôte
    # obliczenie ewentualnej ulgi podatkowej
    réduction = get_réduction(marié, salaire, enfants, impot)
    impot -= réduction
    # wynik
    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}

Uwagi

  • wiersze 6–8: progi podatkowe (patrz paragraf |Calcul de l’impôt brut|);
  • wiersze 11–20: stałe stosowane w obliczeniach podatku;
  • należy zauważyć, że elementy zainicjowane w wierszach 5–20 będą miały charakter globalny dla funkcji, które zamierzamy opisać. Są one zatem znane, o ile funkcja, która z nich korzysta, nie zadeklaruje zmiennych o tych samych nazwach;
  • dane liczbowe w wierszach 5–20 zmieniają się co roku. Tutaj są to dane z 2019 roku;
  • wiersz 25: funkcja [calcul_impôt] przyjmuje trzy parametry:
    • [marié]: tak / nie, wskazuje, czy podatnik pozostaje w związku małżeńskim lub w związku partnerskim;
    • [enfants]: liczba dzieci;
    • [salaire]: jego roczne wynagrodzenie w euro;
  • wiersze 31–33: obliczenie podatku z uwzględnieniem dzieci;
  • wiersze 34–47: wiersze te uwzględniają ograniczenie wysokości ilorazu rodzinnego (patrz punkt |Plafonnement du quotient familial|);
  • wiersze 49–57: w tych wierszach obliczana jest stawka podatkowa podatnika oraz ewentualna dopłata (patrz akapit |Cas des hauts revenus|);
  • wiersze 59–61: obliczenie ewentualnej ulgi (patrz paragraf |Calcul de la décôte|);
  • wiersze 62–64: obliczenie ewentualnej ulgi podatkowej (patrz paragraf |Calcul de la réduction d’impôts|);

Algorytm jest dość złożony i nie będziemy go omawiać bardziej szczegółowo niż wynika to z komentarzy. Algorytm realizuje sposób obliczania podatku opisany w paragrafie |Le problème|.

8.2.5. Funkcja [calcul_impôt_2]

Funkcja [calcul_impôt] wywołuje następującą funkcję [calcul_impôt_2]:


def calcul_impôt_2(marié: str, enfants: int, salaire: int) -> list:
    # stan cywilny: tak, nie
    # dzieci: liczba dzieci
    # wynagrodzenie: roczne wynagrodzenie
    # limity, współczynnik górny, współczynnik dolny: tabele danych umożliwiające obliczenie podatku
    #
    # liczba udziałów
    marié = marié.strip().lower()
    if marié == "oui":
        nb_parts = enfants / 2 + 2
    else:
        nb_parts = enfants / 2 + 1

    # 1 część na dziecko, począwszy od trzeciego
    if enfants >= 3:
        # pół udziału dodatkowo na każde dziecko od trzeciego
        nb_parts += 0.5 * (enfants - 2)

    # dochód podlegający opodatkowaniu
    revenu_imposable = get_revenu_imposable(salaire)
    # dopłata
    surcôte = math.floor(revenu_imposable - 0.9 * salaire)
    # z powodu zaokrągleń
    if surcôte < 0:
        surcôte = 0

    # współczynnik rodzinny
    quotient = revenu_imposable / nb_parts
    # jest umieszczony na końcu tabeli limitów, aby zatrzymać następującą po niej pętlę
    limites[len(limites) - 1] = quotient
    # obliczenie podatku
    i = 0
    while quotient > limites[i]:
        i += 1
        # ponieważ iloraz rodzinny umieszczono na końcu tablicy limitów, poprzednia pętla
    # nie może wykraczać poza tablicę limitów

    # teraz można obliczyć podatek
    impôt = math.floor(revenu_imposable * coeffr[i] - nb_parts * coeffn[i])
    # wynik
    return {"impôt": impôt, "surcôte": surcôte, "taux": coeffr[i]}

Algorytm ten został opisany w punkcie 8.1.1.

8.2.6. Funkcja [get_décôte]

Funkcja [get_décôte] realizuje obliczenie ewentualnej zniżki podatkowej (punkt |Calcul de la décôte|):


# oblicza ewentualną obniżkę
def get_décôte(marié: str, salaire: int, impots: int) -> int:
    # początkowo odliczenie wynosi zero
    décôte = 0
    # maksymalna kwota podatku uprawniająca do ulgi
    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:
        # maksymalna kwota ulgi
        plafond_décôte = PLAFOND_DECOTE_COUPLE if marié == "oui" else PLAFOND_DECOTE_CELIBATAIRE
        # teoretyczna ulga
        décôte = plafond_décôte - 0.75 * impots
        # ulga nie może przekroczyć kwoty podatku
        if décôte > impots:
            décôte = impots

        # brak obniżki <0
        if décôte < 0:
            décôte = 0

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

8.2.7. Funkcja [get_réduction]

Funkcja [get_réduction] realizuje obliczenie ewentualnej ulgi podatkowej (punkt |Calcul de la réduction d’impôts|):


# oblicza ewentualną ulgę
def get_réduction(marié: str, salaire: int, enfants: int, impots: int) -> int:
    # limit dochodów uprawniający do ulgi w wysokości 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

    # dochód podlegający opodatkowaniu
    revenu_imposable = get_revenu_imposable(salaire)
    # ulga
    réduction = 0
    if revenu_imposable < plafond_revenu_pour_réduction:
        # ulga w wysokości 20%
        réduction = 0.2 * impots

    # wynik
    return math.ceil(réduction)

8.2.8. Funkcja [get_revenu_imposable]

Funkcja [get_revenu_imposable] oblicza dochód podlegający opodatkowaniu na podstawie rocznego wynagrodzenia:


# revenu_imposable = salaireAnnuel – ulga
# ulga ma wartość minimalną i maksymalną
# ----------------------------------------
def get_revenu_imposable(salaire: int) -> int:
    # ulga w wysokości 10% wynagrodzenia
    abattement = 0.1 * salaire
    # odliczenie to nie może przekroczyć wartości ABATTEMENT_DIXPOURCENT_MAX
    if abattement > ABATTEMENT_DIXPOURCENT_MAX:
        abattement = ABATTEMENT_DIXPOURCENT_MAX

    # odliczenie nie może być niższe niż ABATTEMENT_DIXPOURCENT_MIN
    if abattement < ABATTEMENT_DIXPOURCENT_MIN:
        abattement = ABATTEMENT_DIXPOURCENT_MIN

    # dochód podlegający opodatkowaniu
    revenu_imposable = salaire - abattement
    # wynik
    return math.floor(revenu_imposable)

8.2.9. Funkcja [record_results]

Funkcja [record_results] zapisuje wyniki obliczeń podatku w pliku tekstowym:


# zapis wyników do pliku tekstowego
# ----------------------------------------
def record_results(results_filename: str, results: list):
    # results_filename: nazwa pliku tekstowego, w którym mają zostać zapisane wyniki
    # results: lista wyników w postaci listy słowników
    # każdy słownik jest zapisany w osobnym wierszu tekstu
    résultats = None
    try:
        # otwarcie pliku wyników
        résultats = codecs.open(results_filename, "w", "utf8")
        # przetwarzanie podatników
        for result in results:
            # wynik zapisywany jest w pliku wyników
            résultats.write(f"{result}\n")
            # kolejny podatnik
    finally:
        # zamknięcie pliku, jeśli został otwarty
        if résultats:
            résultats.close()

8.2.10. Wyniki

Jak już wspomniano, przy użyciu następującego pliku podatników [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

skrypt [main.py] tworzy następujący plik [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}

Wyniki te są zgodne z oficjalnymi danymi z paragrafu |Chiffres officiels|.

Teraz uruchommy tę wersję w oknie konsoli:


(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'

Pojawia się błąd, z którym już się spotkaliśmy: nie znaleziono modułu, w tym przypadku modułu [impots]. Przypominamy, że oznacza to, iż:

  • interpreter języka Python przeszukał po kolei wszystkie katalogi ścieżki Python Path;
  • w żadnym z nich nie znalazł folderu, w którym znajdowałby się skrypt [impots.py];

Wersja [v02] rozwiąże ten problem.