Skip to content

8. Практичне завдання — версія 1

8.1. Задача

Image

Наведена вище таблиця дозволяє розрахувати податок у спрощеному випадку, коли платник податків декларує лише свою заробітну плату. Як зазначено у примітці (1), розрахований таким чином податок є податком до застосування трьох механізмів:

  • обмеження сімейного коефіцієнта, яке застосовується до високих доходів;
  • знижки та зменшення податку, що застосовуються до низьких доходів;

Отже, розрахунок податку включає такі етапи [http://impotsurlerevenu.org/comprendre-le-calcul-de-l-impot/1217-calcul-de-l-impot-2019.php]:

Image

Пропонується написати програму, що дозволяє розрахувати податок платника податків у спрощеному випадку, коли платник податків має лише одну заробітну плату, яку потрібно задекларувати:

8.1.1. Розрахунок валового податку

Валовий податок можна розрахувати таким чином:

Спочатку обчислюємо кількість часток платника податків:

  • кожен з батьків дає 1 частку;
  • двоє перших дітей приносять по 1/2 частки;
  • наступні діти — по одній частці кожен:

Отже, кількість часток становить:

  • nbParts=1+nbEnfants*0,5+(nbEnfants-2)*0,5, якщо працівник не одружений;
  • nbParts = 2 + nbEnfants * 0,5 + (nbEnfants - 2) * 0,5, якщо він одружений;
    • де nbEnfants — кількість дітей;
  • розраховується оподатковуваний дохід R = 0,9 * S, де S — річна заробітна плата;
  • розраховується сімейний коефіцієнт QF = R / nbParts;
  • розраховується валовий податок I на основі таких даних (2019 р.):
9964
0
0
27519
0,14
1394,96
73779
0,3
5798
156244
0,4
13913,69
0
0,45
20163,45

Кожен рядок має 3 поля: champ1, champ2, champ3. Щоб обчислити податок I, шукаємо перший рядок, у якому QF <= поле1, і беремо значення з цього рядка. Наприклад, для працівника, який перебуває у шлюбі, має двох дітей і отримує річну заробітну плату S у розмірі 50000 євро:

Оподатковуваний дохід: R = 0,9 * S = 45000

Кількість часток: nbParts = 2 + 2 * 0,5 = 3

Сімейний коефіцієнт: QF = 45 000 / 3 = 15 000

Перший рядок, де QF <= поле1, виглядає так:

    27519    0.14    1394.96

Тоді податок I дорівнює 0,14*R – 1394,96*nbParts=[0,14*45000-1394,96*3]=2115. Податок округлюється до найближчого нижчого євро.

Якщо вже в першому рядку виконується умова QF <= поле1, то податок дорівнює нулю.

Якщо QF таке, що умова QF<=поле1 ніколи не виконується, то використовуються коефіцієнти останнього рядка. У даному випадку:

    0    0.45    20163.45

що дає валовий податок I = 0,45*R – 20163,45*nbParts.

8.1.2. Обмеження сімейного коефіцієнта

Image

Щоб з’ясувати, чи застосовується обмеження сімейного коефіцієнта QF, потрібно перерахувати валовий податок без урахування дітей. Знову ж таки, для працівника, який перебуває у шлюбі, має двох дітей та отримує річну заробітну плату S у розмірі 50000 євро:

Оподатковуваний дохід: R = 0,9 * S = 45 000

Кількість часток: nbParts = 2 (дітей більше не враховують)

Сімейний коефіцієнт: QF = 45 000 / 2 = 22 500

Перший рядок, де QF <= поле1, виглядає так:

    27519    0.14    1394.96

Податок I дорівнює 0,14*R – 1394,96*nbParts=[0,14*45000-1394,96*2]=3510.

Максимальний дохід, пов’язаний з дітьми: 1551 * 2 = 3102 євро

Мінімальний податок: 3510 – 3102 = 408 євро

Валовий податок із 3 частками, який вже розраховано як 2115 євро, перевищує мінімальний податок у розмірі 408 євро, тому сімейне обмеження в цьому випадку не застосовується.

Загалом, валовий податок перевищує (податок1, податок2), де:

  • [impôt1] — валовий податок, розрахований з урахуванням дітей;
  • [impôt2] — валовий податок, розрахований без урахування дітей та зменшений на максимальну суму пільги (у даному випадку 1551 євро за півчастини), пов’язану з дітьми;

8.1.3. Розрахунок знижки

Image

Знову ж таки, для працівника, який перебуває у шлюбі, має двох дітей та отримує річну заробітну плату S у розмірі 50 000 євро:

Валовий податок (2115), отриманий на попередньому етапі, є меншим за 2627 євро для подружжя (1595 євро для одинокої особи): отже, застосовується знижка. Її розраховують за такою формулою:

знижка = поріг (для подружжя = 1970 / для одинокої особи = 1196) – 0,75 * валовий податок

знижка = 1970 – 0,75 × 2115 = 383,75, округлено до 384 євро.

Новий валовий податок = 2115 – 384 = 1731 євро

8.1.4. Розрахунок податкової знижки

Image

Нижче певного порогу до валового податку, розрахованого за попередніми розрахунками, застосовується знижка у розмірі 20 %. У 2019 році пороги є такими:

  • одинокі особи: 21 037 євро;
  • для подружжя: 42 074 євро; (цифра 37 968, використана у наведеному вище прикладі, здається помилковою);

Цей поріг збільшується на величину: 3797 * (кількість півчастин, що припадають на дітей).

Знову ж таки, для працівника, який перебуває у шлюбі, має двох дітей та отримує річну заробітну плату S у розмірі 50 000 євро:

  • його оподатковуваний дохід (45 000 євро) є меншим за поріг (42 074 + 2 × 3797) = 49 668 євро;
  • отже, він має право на зменшення податку на 20 %: 1731 * 0,2 = 346,2 євро, округлено до 347 євро;
  • валовий податок платника податків становить: 1731 – 347 = 1384 євро;

8.1.5. Розрахунок чистого податку

На цьому наш розрахунок завершується: чистий податок до сплати становитиме 1384 євро. Насправді платник податків може скористатися іншими пільгами, зокрема за пожертви на користь організацій, що діють в інтересах суспільства або загального блага.

8.1.6. Випадок високих доходів

Наш попередній приклад відповідає більшості випадків найманих працівників. Однак розрахунок податку відрізняється у випадку високих доходів.

8.1.6.1. Обмеження 10-відсоткової знижки на річний дохід

У більшості випадків оподатковуваний дохід обчислюється за формулою: R = 0,9 * S, де S — річна заробітна плата. Це називається 10-відсотковим зниженням. Для цього зниження встановлено верхню межу. У 2019 році:

  • вона не може перевищувати 12 502 євро;
  • вона не може бути меншою за 437 євро;

Розглянемо випадок неодруженого працівника без дітей із річною заробітною платою 200 000 євро:

  • зниження на 10 % становить 20 000 євро > 12 502 євро. Отже, воно зменшується до 12 502 євро;

8.1.6.2. Обмеження сімейного коефіцієнта

Розглянемо випадок, коли застосовується обмеження сімейного коефіцієнта, описане в розділі |Обмеження сімейного коефіцієнта|. Розглянемо випадок подружжя з трьома дітьми та річним доходом 100 000 євро. Повторимо етапи розрахунку:

  • відрахування у розмірі 10 % становить 10 000 євро < 12 502 євро. Отже, оподатковуваний дохід R дорівнює 100 000 – 10 000 = 90 000 євро;
  • пара має nbParts = 2 + 0,5 × 2 + 1 = 4 частки;
  • отже, їхній сімейний коефіцієнт становить QF = R / nbParts = 90 000 / 4 = 22 500 євро;
  • їхній валовий податок I1 з урахуванням дітей становить I1=0,14*90000-1394,96*4= 7020 євро;
  • його валовий податок I2 без дітей:
  • QF = 90 000 / 2 = 45 000 євро;
  • I2 = 0,3 × 90 000 – 5 798 × 2 = 15 404 євро;
  • правило обмеження сімейного коефіцієнта передбачає, що виграш, який приносять діти, не може перевищувати (1551 × 4 півчастини) = 6204 євро. Однак у даному випадку він становить I2-I1 = 15404 – 7020 = 8384 євро, тобто перевищує 6204 євро;
  • отже, валовий податок перераховується як I3 = I2-6204 = 15404 – 6204 = 9200 євро;

Ця подружня пара не матиме ані знижки, ані пільги, і її остаточний податок становитиме 9200 євро.

8.1.7. Офіційні цифри

Розрахунок податку є складним. У цьому документі розрахунки будуть проводитися на таких прикладах. Результати отримано за допомогою симулятора податкової адміністрації |https://www3.impots.gouv.fr/simulateur/calcul_impot/2019/simplifie/index.htm|:

Платник податків
Офіційні результати
Результати алгоритму, наведеного в документі
Пара з двома дітьми та річним доходом 55555 євро
Податок = 2815 євро
Ставка податку = 14 %
Податок = 2814 євро
Ставка податку = 14 %
Сім’я з двома дітьми та річним доходом 50 000 євро
Податок = 1385 євро
Знижка = 720 євро
Знижка = 0 євро
Ставка податку = 14 %
Податок = 1384 євро
Знижка = 384 євро
Знижка = 347 євро
Ставка податку = 14 %
Пара з трьома дітьми та річним доходом 50 000 євро
Податок = 0 євро
Знижка = 384 євро
Знижка = 346 євро
Ставка оподаткування = 14 %
Податок = 0 євро
знижка = 720 євро
Знижка = 0 євро
Ставка податку = 14 %
Одинока особа з 2 дітьми та річним доходом 100 000 євро
Податок = 19 884 євро
Знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 41 %
Податок = 19 884 євро
Надбавка = 4480 євро
знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 41 %
Одинока особа з 3 дітьми та річним доходом 100 000 євро
Податок = 16 782 євро
Знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 41 %
Податок = 16 782 євро
Надбавка = 7176 євро
знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 41 %
Подружжя з трьома дітьми та річним доходом 100 000 євро
Податок = 9200 євро
знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 30 %
Податок = 9200 євро
Надбавка = 2180 євро
знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 30 %
Пара з 5 дітьми та річним доходом 100 000 євро
Податок = 4230 євро
Знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 14 %
Податок = 4230 євро
знижка = 0 євро
Знижка = 0 євро
Ставка податку = 14 %
Одинока особа без дітей із річним доходом 100 000 євро
Податок = 22 986 євро
Знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 41 %
Податок = 22 986 євро
Надбавка = 0 євро
знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 41 %
Подружжя з двома дітьми та річним доходом 30 000 євро
Податок = 0 євро
Знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 0 %
Податок = 0 євро
знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 0 %
Одинока особа без дітей із річним доходом 200 000 євро
Податок = 64 211 євро
знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 45 %
Податок = 64 210 євро
Надбавка = 7498 євро
знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 45 %
Подружжя з трьома дітьми та річним доходом 200 000 євро
Податок = 42 843 євро
Знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 41 %
Податок = 42 842 євро
Надбавка = 17 283 євро
знижка = 0 євро
Знижка = 0 євро
Ставка оподаткування = 41 %

У наведеному вище прикладі надбавкою називають суму, яку додатково сплачують особи з високими доходами через два фактори:

  • обмеження розміру податкової пільги 10 % від річного доходу;
  • обмеження сімейного коефіцієнта;

Цей показник не вдалося перевірити, оскільки симулятор податкової адміністрації його не надає.

Видно, що алгоритм, наведений у документі, щоразу обчислює правильну суму податку, однак із похибкою в 1 євро. Ця похибка зумовлена округленням. Усі суми іноді округлюються до вищого, іноді — до нижчого євро. Оскільки я не знав офіційних правил, грошові суми в алгоритмі документа були округлені:

  • до вищого євро — для знижок та пільг;
  • до нижчого євро — для надбавок та остаточного податку;

Ми розробимо кілька версій програми для розрахунку податку.

8.2. Версія 1

Image

8.2.1. Головний скрипт

Ми представляємо першу програму, в якій:

  • дані, необхідні для розрахунку податку, жорстко задані в коді у вигляді списків та констант;
  • дані про платників податків (сімейний стан, діти, заробітна плата) містяться у першому текстовому файлі [taxpayersdata.txt];
  • результати розрахунку податку (статус у шлюбі, діти, заробітна плата, податок) зберігаються у другому текстовому файлі [résultats.txt];

Скрипт [v-01/main.py] має такий вигляд:


# модулі
import sys

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

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

# константи
# файл платників податків
DATA = "./data/taxpayersdata.txt"
# файл результатів
RESULTATS = "./data/résultats.txt"

try:
    # читання даних про платників податків
    tax_payers = get_taxpayers_data(DATA)
    # список результатів
    results = []
    # розрахунок податку платників податків
    for tax_payer in tax_payers:
        # розрахунок податку повертає словник ключів
        # ['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'])
        # словник додано до списку результатів
        results.append(result)
    # результати зберігаються
    record_results(RESULTATS, results)
except BaseException as erreur:
    # можуть виникнути різні помилки: відсутність файлу, неправильний вміст файлу
    # виводиться повідомлення про помилку та закривається програма
    print(f"l'erreur suivante s'est produite : {erreur}]\n")
    sys.exit()

Примітки

  • рядок 4: використовується модуль [impots.v01.modules.impôts_module_01]. Нагадуємо, що цей шлях вимірюється від кореневого каталогу проєкту PyCharm;
  • рядок 10: файл [data/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

Кожен рядок представляє кортеж із трьох елементів [marié / pacsé ou pas, nombre d'enfants, salaire annuel en euros].

  • рядок 12: файл, у який будуть записані результати розрахунку податку для кожного з платників податків із файлу [taxpayersdata.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}
  • рядок 16: витягуються дані про платників податків, що містяться у файлі [taxpayersdata.txt]. Витягується список словників ключів [marié, enfants, salaire], кожен словник представляє одного платника податків;
  • рядки 17–25: обчислюється податок платників податків зі списку [taxPayers]. Отримується список [results], кожен елемент якого знову є словником ключів [marié, enfants, salaire, impôt, surcôte, décôte, réduction, taux];
  • рядок 27: список результатів [results] записується у файл [résultats.txt] у формі, показаній вище;
  • рядки 28–32: перехоплюються всі винятки, які можуть виникнути в модулі [impots.v01.modules.impôts_module_01];

Тепер детально розглянемо три функції, які використовує скрипт [main]:

  • [get_taxpayers_data]: для зчитування даних про платників податків;
  • [calcul_impôt]: для розрахунку податку платників;
  • [record_results]: для запису результатів у текстовий файл;

Усі ці функції містяться в модулі [impots.modules.impôts_module_01].

8.2.2. Модуль [impots.v01.shared.impôts_module_01]

Функції, необхідні для розрахунку податку, зібрано в модулі [impots.v01.shared.impôts_module_01]:

Image

  • у [1]: визначення констант для розрахунку податку;
  • у [2] — перелік функцій модуля;

8.2.3. Функція [get_taxpayers_data]

Функція [get_taxpayers_data] має такий вигляд:


# імпорт
import codecs


# зчитування даних платників податків
# ----------------------------------------
def get_taxpayers_data(taxpayers_filename: str) -> list:
    # читання даних платників податків
    file = None
    try:
        # список платників податків
        taxpayers = []
        # відкриття файлу
        file = codecs.open(taxpayers_filename, "r", "utf8")
        # зчитування першого рядка файлу платників податків
        ligne = file.readline().strip()
        # поки залишається хоча б один рядок для обробки
        while ligne != '':
            # витягуються 3 поля «одружений», «діти», «зарплата», що складають цей рядок
            (marié, enfants, salaire) = ligne.split(",")
            # додаємо їх до списку платників податків
            taxpayers.append({'marié': marié.strip().lower(), 'enfants': int(enfants), 'salaire': int(salaire)})
            # зчитуємо новий рядок з файлу платників податків
            ligne = file.readline().strip()
        # виводимо результат
        return taxpayers
    finally:
        # закриваємо файл, якщо він був відкритий
        if file:
            file.close()

Примітки

  • рядок 7: [taxpayers_filename] — це ім’я файлу, що обробляється. Функція повертає список;
  • рядки 18–24: цикл обробки рядків [marié, enfants, salaire] з текстового файлу;
  • рядок 20: витягуються три елементи рядка. Тут припускається, що рядок є синтаксично правильним, тобто містить саме ті три очікувані елементи;
  • рядок 22: створюється словник із ключами [marié, enfants, salaire], і цей словник додається до списку [taxPayers];
  • рядок 26: після обробки файлу повертається список [taxPayers];
  • рядки 10–30: зверніть увагу, що ми не додали умову [catch] до [try] у рядку 10. Умова [catch] не є обов’язковою. У рядку 27 додано оператор [finally] для закриття текстового файлу в будь-якому випадку, незалежно від того, чи сталася помилка;
  • ця структура try / finally пропускає можливе виключення (немає catch). Це виключення буде передано до головного скрипта [main], який зупиниться та відобразить виключення (див. параграф |Головний скрипт|). Цей механізм було використано для більшості функцій модуля;

8.2.4. Функція [calcul_impôt]

Функція [calcul_impôt] має такий вигляд:


# імпорт
import codecs
import math

# податкові шкали за 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]

# константи для розрахунку податку за 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


# розрахунок податку
# ----------------------------------------
def calcul_impôt(marié: str, enfants: int, salaire: int) -> dict:
    # одружений: так, ні
    # діти: кількість дітей
    # зарплата: річна зарплата
    # ліміти, коефіцієнт, коефіцієнт: таблиці даних, що дозволяють розрахувати податок
    #
    # розрахунок податку з урахуванням дітей
    result1 = calcul_impôt_2(marié, enfants, salaire)
    impot1 = result1["impôt"]
    # розрахунок податку без урахування дітей
    if enfants != 0:
        result2 = calcul_impôt_2(marié, 0, salaire)
        impot2 = result2["impôt"]
        # застосування обмеження сімейного коефіцієнта
        if enfants < 3:
            # PLAFOND_QF_DEMI_PART євро для перших двох дітей
            impot2 = impot2 - enfants * PLAFOND_QF_DEMI_PART
        else:
            # PLAFOND_QF_DEMI_PART євро за перших двох дітей, удвічі більше — за наступних
            impot2 = impot2 - 2 * PLAFOND_QF_DEMI_PART - (enfants - 2) * 2 * PLAFOND_QF_DEMI_PART
    else:
        impot2 = impot1
        result2 = result1

    # береться найвищий податок із відповідною ставкою та надбавкою
    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"]

    # розрахунок можливого зниження
    décôte = get_décôte(marié, salaire, impot)
    impot -= décôte
    # розрахунок можливого зменшення податку
    réduction = get_réduction(marié, salaire, enfants, impot)
    impot -= réduction
    # результат
    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}

Примітки

  • рядки 6–8: податкові шкали (див. розділ |Розрахунок валового податку|);
  • рядки 11–20: константи для розрахунку податку;
  • варто зауважити, що елементи, ініціалізовані у рядках 5–20, будуть глобальними для функцій, які ми опишемо. Отже, вони залишаються відомими, доки функція, яка їх використовує, не оголошує змінних з такими самими іменами;
  • цифри в рядках 5–20 змінюються щороку. Тут наведено дані за 2019 рік;
  • рядок 25: функція [calcul_impôt] приймає три параметри:
    • [marié]: так/ні, вказує, чи перебуває платник податків у шлюбі або в цивільному партнерстві;
    • [enfants]: кількість дітей;
    • [salaire]: його річний заробіток у євро;
  • рядки 31–33: розрахунок податку з урахуванням дітей;
  • рядки 34–47: у цих рядках реалізовано обмеження сімейного коефіцієнта (див. розділ |Обмеження сімейного коефіцієнта|);
  • рядки 49–57: у цих рядках розраховується ставка оподаткування платника податків, а також можлива надбавка (див. параграф |Випадки високих доходів|);
  • рядки 59–61: розрахунок можливої знижки (див. розділ |Розрахунок знижки|);
  • рядки 62–64: розрахунок можливого зменшення суми податку до сплати (див. розділ |Розрахунок зменшення податку|);

Алгоритм є досить складним, і ми не будемо детально його описувати, окрім того, що зазначено в коментарях. Алгоритм реалізує спосіб розрахунку податку, описаний у розділі |Проблема|.

8.2.5. Функція [calcul_impôt_2]

Функція [calcul_impôt] викликає наступну функцію [calcul_impôt_2]:


def calcul_impôt_2(marié: str, enfants: int, salaire: int) -> list:
    # одружений: так, ні
    # діти: кількість дітей
    # зарплата: річна зарплата
    # ліміти, коефіцієнт, коефіцієнт: таблиці даних, що дозволяють розрахувати податок
    #
    # кількість часток
    marié = marié.strip().lower()
    if marié == "oui":
        nb_parts = enfants / 2 + 2
    else:
        nb_parts = enfants / 2 + 1

    # 1 частка на дитину, починаючи з третьої
    if enfants >= 3:
        # півчастки додатково за кожну дитину, починаючи з третьої
        nb_parts += 0.5 * (enfants - 2)

    # оподатковуваний дохід
    revenu_imposable = get_revenu_imposable(salaire)
    # надбавка
    surcôte = math.floor(revenu_imposable - 0.9 * salaire)
    # для виправлення округлень
    if surcôte < 0:
        surcôte = 0

    # сімейний коефіцієнт
    quotient = revenu_imposable / nb_parts
    # встановлюється в кінці таблиці обмежень для зупинки наступного циклу
    limites[len(limites) - 1] = quotient
    # розрахунок податку
    i = 0
    while quotient > limites[i]:
        i += 1
        # оскільки коефіцієнт розміщено в кінці таблиці обмежень, попередній цикл
    # не може виходити за межі таблиці обмежень

    # тепер можна обчислити податок
    impôt = math.floor(revenu_imposable * coeffr[i] - nb_parts * coeffn[i])
    # результат
    return {"impôt": impôt, "surcôte": surcôte, "taux": coeffr[i]}

Цей алгоритм описано в розділі 8.1.1.

8.2.6. Функція [get_décôte]

Функція [get_décôte] реалізує обчислення можливої знижки з податку (розділ |Обчислення знижки|):


# розраховує можливу знижку
def get_décôte(marié: str, salaire: int, impots: int) -> int:
    # спочатку знижка дорівнює нулю
    décôte = 0
    # максимальна сума податку для отримання знижки
    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:
        # максимальна сума знижки
        plafond_décôte = PLAFOND_DECOTE_COUPLE if marié == "oui" else PLAFOND_DECOTE_CELIBATAIRE
        # теоретична знижка
        décôte = plafond_décôte - 0.75 * impots
        # знижка не може перевищувати суму податку
        if décôte > impots:
            décôte = impots

        # знижка <0
        if décôte < 0:
            décôte = 0

    # результат
    return math.ceil(décôte)

8.2.7. Функція [get_réduction]

Функція [get_réduction] реалізує розрахунок можливого зменшення суми податку до сплати (розділ |Розрахунок зменшення податку|):


# розраховує можливе зниження
def get_réduction(marié: str, salaire: int, enfants: int, impots: int) -> int:
    # максимальний рівень доходу для отримання права на знижку в розмірі 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

    # оподатковуваний дохід
    revenu_imposable = get_revenu_imposable(salaire)
    # знижка
    réduction = 0
    if revenu_imposable < plafond_revenu_pour_réduction:
        # знижка у розмірі 20 %
        réduction = 0.2 * impots

    # результат
    return math.ceil(réduction)

8.2.8. Функція [get_revenu_imposable]

Функція [get_revenu_imposable] розраховує оподатковуваний дохід на основі річної заробітної плати:


# revenu_imposable = salaireAnnuel — податкова пільга
# знижка має мінімальний та максимальний розмір
# ----------------------------------------
def get_revenu_imposable(salaire: int) -> int:
    # знижка у розмірі 10 % від заробітної плати
    abattement = 0.1 * salaire
    # ця знижка не може перевищувати ABATTEMENT_DIXPOURCENT_MAX
    if abattement > ABATTEMENT_DIXPOURCENT_MAX:
        abattement = ABATTEMENT_DIXPOURCENT_MAX

    # знижка не може бути меншою за ABATTEMENT_DIXPOURCENT_MIN
    if abattement < ABATTEMENT_DIXPOURCENT_MIN:
        abattement = ABATTEMENT_DIXPOURCENT_MIN

    # оподатковуваний дохід
    revenu_imposable = salaire - abattement
    # результат
    return math.floor(revenu_imposable)

8.2.9. Функція [record_results]

Функція [record_results] записує результати розрахунку податку у текстовий файл:


# запис результатів у текстовий файл
# ----------------------------------------
def record_results(results_filename: str, results: list):
    # results_filename: ім’я текстового файлу, куди слід записати результати
    # results: список результатів у вигляді списку словників
    # кожен словник записується в окремому рядку тексту
    résultats = None
    try:
        # відкриття файлу з результатами
        résultats = codecs.open(results_filename, "w", "utf8")
        # обробка даних
        for result in results:
            # запис результату у файл результатів
            résultats.write(f"{result}\n")
            # наступний платник податків
    finally:
        # закриття файлу, якщо він був відкритий
        if résultats:
            résultats.close()

8.2.10. Результати

Як уже зазначалося, за допомогою такого файлу платників податків [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

скрипт [main.py] створює такий файл [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}

Ці результати відповідають офіційним даним, наведеним у розділі |Офіційні дані|.

Тепер запустимо цю версію у вікні консолі:


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

Ми знову стикаємося з помилкою, яка вже траплялася раніше: модуль не знайдено, у даному випадку — модуль [impots]. Нагадаємо, що це означає:

  • інтерпретатор Python по черзі обійшов усі папки в Python Path;
  • у жодній з них він не знайшов папки, в якій міг би бути скрипт [impots.py];

Версія [v02] вирішить цю проблему.