Skip to content

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

4.1. Задача

Image

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

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

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

Image

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

4.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,41
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.

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

Image

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

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

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

Сімейний коефіцієнт: QF=45000/2=22500

Перший рядок, у якому 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 євро за півчастини), пов’язану з дітьми;

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

Image

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

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

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

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

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

4.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 євро;

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

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

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

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

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

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

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

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

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

4.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 євро.

4.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 євро. Ця похибка зумовлена округленням. Усі суми іноді округлюються до вищого, іноді — до нижчого євро. Оскільки я не знав офіційних правил, грошові суми в алгоритмі документа були округлені:

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

Надалі будуть проведені тести для перевірки правильності результатів. Вони будуть виконані на прикладах із попередньої таблиці з допустимою похибкою в 1 євро.

4.2. Структура скриптів

Image

4.3. Версія 1

4.3.1. Алгоритм

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

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

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


<?php

// строгі типи для параметрів функцій
declare(strict_types=1);

// глобальні константи
define("PLAFOND_QF_DEMI_PART", 1551);
define("PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION", 21037);
define("PLAFOND_REVENUS_COUPLE_POUR_REDUCTION", 42074);
define("VALEUR_REDUC_DEMI_PART", 3797);
define("PLAFOND_DECOTE_CELIBATAIRE", 1196);
define("PLAFOND_DECOTE_COUPLE", 1970);
define("PLAFOND_IMPOT_COUPLE_POUR_DECOTE", 2627);
define("PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE", 1595);
define("ABATTEMENT_DIXPOURCENT_MAX", 12502);
define("ABATTEMENT_DIXPOURCENT_MIN", 437);

// визначення локальних констант
$DATA = "taxpayersdata.txt";
$RESULTATS = "resultats.txt";
$limites = array(9964, 27519, 73779, 156244, 0);
$coeffR = array(0, 0.14, 0.3, 0.41, 0.45);
$coeffN = array(0, 1394.96, 5798, 13913.69, 20163.45);

// читання даних
$data = fopen($DATA, "r");
if (!$data) {
  print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
  exit;
}

// відкриття файлу результатів
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
  print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
  exit;
}

// обробка поточного рядка файлу даних
while ($ligne = fgets($data, 100)) {
  // видалення можливого символу кінця рядка
  $ligne = cutNewLineChar($ligne);
  // отримано 3 поля «одружений:діти:зарплата», що утворюють $ligne
  list($marié, $enfants, $salaire) = explode(",", $ligne);
  // розраховується податок
  $result = calculImpot($marié, (int) $enfants, (float) $salaire, $limites, $coeffR, $coeffN);
  // записуємо результат у файл результатів
  $result = ["marié" => $marié, "enfants" => $enfants, "salaire" => $salaire] + $result;
  fputs($résultats, \json_encode($result, JSON_UNESCAPED_UNICODE) . "\n");
  // наступні дані
}
// закриваємо файли
fclose($data);
fclose($résultats);

// кінець
exit;

// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne): string {
  // видаляється маркер кінця рядка з $ligne, якщо він існує
  $L = strlen($ligne);  // довжина рядка
  while (substr($ligne, $L - 1, 1) === "\n" or substr($ligne, $L - 1, 1) === "\r") {
    $ligne = substr($ligne, 0, $L - 1);
    $L--;
  }
  // кінець
  return($ligne);
}

// розрахунок податку
// --------------------------------------------------------------------------
function calculImpot(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {

  // результат
  return ["impôt" => floor($impot), "surcôte" => $surcôte, "décôte" => $décôte, "réduction" => $réduction, "taux" => $taux];
}

// --------------------------------------------------------------------------
function calculImpot2(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {

  // результат
  return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}

// revenuImposable=річна зарплата-податкова пільга
// податкова пільга має мінімальне та максимальне значення
function getRevenuImposable(float $salaire): float {

  // результат
  return floor($revenuImposable);
}

// розраховує можливе зниження
function getDecote(string $marié, float $salaire, float $impots): float {

  // результат
  return ceil($décôte);
}

// розраховує можливе зниження
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {
  /
  // результат
  return ceil($réduction);
}

Файл даних 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

Файл 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}

Коментарі

  • рядок 4: забезпечується суворе дотримання типів параметрів функцій;
  • рядки 7–16: визначення всіх констант, необхідних для розрахунку податку;
  • рядок 19: ім’я текстового файлу, що містить дані про платників податків (одружений, діти, заробітна плата);
  • рядок 20: ім’я текстового файлу, що містить результати (статус шлюбу, діти, заробітна плата, податок) розрахунку податку;
  • рядки 21–23: три таблиці даних, що визначають різні податкові ставки для розрахунку податку;
  • рядки 26–30: відкриття у режимі читання [r] файлу даних платників податків. Функція [fopen] повертає логічне значення FALSE, якщо відкрити файл не вдалося;
  • рядки 33–37: відкриття файлу результатів у режимі запису за допомогою функції [w];
  • рядки 40–51: цикл читання рядків (чоловік/дружина, діти, заробітна плата) з файлу даних платників податків;
  • рядок 40: функція [fgets] зчитує 100 символів і зупиняється на першому знаку кінця рядка, який зустрічається. Тут усі рядки містять менше 100 символів. Якщо зустрічається маркер кінця рядка, він включається до поверненого рядка. Коли досягається кінець файлу, функція [fgets] повертає значення FALSE;
  • рядок 42: маркер кінця рядка видаляється;
  • рядок 44: витягуються складові (чоловік, діти, заробітна плата) цього рядка;
  • рядок 46: обчислюється податок. Результат повертається у вигляді асоціативного масиву (рядок 76);
  • рядок 48: до масиву, отриманого раніше, додаються ключі [marié, enfants, salaire];
  • рядок 49: результат зберігається у файлі результатів у вигляді рядка jSON;
  • рядки 53–54: після повного опрацювання файлу даних платників податків файли закриваються;
  • рядок 60: функція, яка видаляє маркер кінця рядка з рядка $ligne. Маркером кінця рядка є рядок "\r\n" у системах Windows та "\n" у системах Unix. Результатом є вхідний рядок без маркера кінця рядка.
  • рядки 63–64: substr($chaîne, $début,$taille) — це підрядок $chaîne, що починається з символу $début і містить не більше $taille символів;

Функція [calculImpot] визначається наступним чином:


// глобальні константи
define("PLAFOND_QF_DEMI_PART", 1551);

// розрахунок податку
// --------------------------------------------------------------------------
function calculImpot(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
  // $marié: так, ні
  // $enfants: кількість дітей
  // $salaire: річний оклад
  // $limites, $coeffR, $coeffN: таблиці даних, що дозволяють розрахувати податок
  //
  // розрахунок податку з урахуванням дітей
  $result1 = calculImpot2($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
  $impot1 = $result1["impôt"];
  // розрахунок податку без дітей
  if ($enfants != 0) {
    $result2 = calculImpot2($marié, 0, $salaire, $limites, $coeffR, $coeffN);
    $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 = getDecote($marié, $salaire, $impot);
  $impot -= $décôte;
  // розрахунок можливого зменшення податку
  $réduction = getRéduction($marié, $salaire, $enfants, $impot);
  $impot -= $réduction;
  // результат
  return ["impôt" => floor($impot), "surcôte" => $surcôte, "décôte" => $décôte, "réduction" => $réduction, "taux" => $taux];
}

// --------------------------------------------------------------------------
function calculImpot2(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {

  // результат
  return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}

// revenuImposable=річназарплата-пільга
// 10-відсоткова знижка має мінімальне та максимальне значення
function getRevenuImposable(float $salaire): float {

}

// розраховує можливе зниження
function getDecote(string $marié, float $salaire, float $impots): float {

  // результат
  return ceil($décôte);
}

// розраховує можливе зменшення
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {

  // результат
  return ceil($réduction);
}

Коментарі

  • рядок 10: валовий податок розраховується з урахуванням дітей. Отримуємо результат у вигляді ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]] з:
    • [‘impôt’] — валовий податок;
    • [‘surcôte’]: сума надбавки, якщо така є. Вона застосовується, коли пільга у розмірі 10 % перевищує поріг у 12 502 євро;
    • [‘taux’]: ставка оподаткування платника податків;
  • рядок 11: валовий податок [impot1], що підлягає сплаті;
  • рядки 13–14: якщо платник податків має принаймні одну дитину, розрахунок податку проводиться повторно з тими самими даними, але з урахуванням 0 дітей. Цей другий розрахунок необхідний для того, щоб перевірити, чи перевищує пільга за дітей (nbParts*coeffN) певний поріг;
  • рядок 15: валовий податок [impot2], що підлягає сплаті;
  • рядки 16–23: для валового податку [impot2] тепер враховуються діти: кожна 1/2 частки, що надається дітьми, дає право на зменшення на [PLAFOND_QF_DEMI_PART] євро;
  • рядки 25–26: випадок, коли платник податків не має дітей. У цьому випадку обчислення [impot2] не потрібне. Воно дорівнює [impot1];
  • рядки 29–37: було розраховано два суми брутто податку [impot1, impot2]. Податкова служба бере до уваги більшу з них. Отримуємо суму брутто податку [impot];
  • рядки 39–40: валова сума [impot] може підлягати знижці;
  • рядки 42–43: валова сума [impot] може бути зменшена;
  • рядок 45: [impot] тепер є чистим податком до сплати. Повертаємо результати;

Функція [calculImpot2] виглядає наступним чином:


// --------------------------------------------------------------------------
function calculImpot2(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
  // $marié: так, ні
  // $enfants: кількість дітей
  // $salaire: річний оклад
  // $limites, $coeffR, $coeffN: таблиці даних, що дозволяють розрахувати податок
  //
  // кількість часток
  $marié = strtolower($marié);
  if ($marié === "oui") {
    $nbParts = $enfants / 2 + 2;
  } else {
    $nbParts = $enfants / 2 + 1;
  }
  // 1 частка на дитину, починаючи з третьої
  if ($enfants >= 3) {
    // півчастки додатково за кожну дитину, починаючи з третьої
    $nbParts += 0.5 * ($enfants - 2);
  }
  // оподатковуваний дохід
  $revenuImposable = getRevenuImposable($salaire);
  // надбавка
  $surcôte = floor($revenuImposable - 0.9 * $salaire);
  // за проблеми з округленням
  if ($surcôte < 0) {
    $surcôte = 0;
  }
  // сімейний коефіцієнт
  $quotient = $revenuImposable / $nbParts;
  // вказується в кінці таблиці обмежень для зупинки наступного циклу
  $limites[count($limites) - 1] = $quotient;
  // розрахунок податку
  $i = 0;
  while ($quotient > $limites[$i]) {
    $i++;
  }
  // оскільки $quotient розміщено в кінці таблиці $limites, попередній цикл
  // не може виходити за межі масиву $limites
  // тепер можна обчислити податок
  $impôt = floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
  // результат
  return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}

// revenuImposable = річна зарплата — податкова пільга
// податкова пільга має мінімальний та максимальний розмір
function getRevenuImposable(float $salaire): float {
  
  // результат
  return floor($revenuImposable);
}

Коментарі

  • тут застосовується розрахунок податку за прогресивною шкалою;
  • рядок 9: strtolower($chaîne) перетворює $chaîne на малі літери;
  • рядки 10–19: обчислення кількості часток платника податків;
  • рядок 21: оподатковуваний дохід обчислюється за допомогою функції. Адже ми бачили, що він не завжди дорівнює 0,9*revenusAnnuels. Знижка у розмірі 10 % обмежена сумою 12502 євро;
  • рядок 23: розрахунок можливої надбавки, якщо оподатковуваний дохід перевищує 0,9*revenusAnnuels;
  • рядки 25–27: враховують той факт, що через похибки округлення іноді отримуємо значення [$surcôte=-1];
  • рядок 29: сімейний коефіцієнт;
  • рядки 30–36: цей коефіцієнт дозволяє визначити податкову групу платника податків;
  • рядок 40: після визначення податкової групи платника податків можна розрахувати його валовий податок. Функція floor($x) повертає ціле значення, безпосередньо менше за [$x];
  • рядок 42: виводиться розрахована інформація;

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


// глобальні константи
define("ABATTEMENT_DIXPOURCENT_MAX", 12502);
define("ABATTEMENT_DIXPOURCENT_MIN", 437);

// revenuImposable=річна-зарплата-відрахування
// податкова пільга має мінімальне та максимальне значення
function getRevenuImposable(float $salaire): float {
  // відрахування у розмірі 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;
  }
  // оподатковуваний дохід
  $revenuImposable = $salaire - $abattement;
  // фінансовий результат
  return floor($revenuImposable);
}

Коментарі

  • рядок 5: стандартна знижка становить 10 % від річної заробітної плати;
  • рядки 7–9: відрахування не може перевищувати максимального відрахування [ABATTEMENT_DIXPOURCENT_MAX];
  • рядки 10–13: відрахування не може бути меншим за мінімальне відрахування [ABATTEMENT_DIXPOURCENT_MIN];
  • рядок 15: розрахунок оподатковуваного доходу;

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


// загальні константи
define("PLAFOND_DECOTE_CELIBATAIRE", 1196);
define("PLAFOND_DECOTE_COUPLE", 1970);
define("PLAFOND_IMPOT_COUPLE_POUR_DECOTE", 2627);
define("PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE", 1595);

// розраховує можливу знижку
function getDecote(string $marié, float $salaire, float $impots): float {
  // спочатку знижка дорівнює нулю
  $décôte = 0;
  // максимальна сума податку для отримання знижки
  $plafondImpôtPourDécôte = $marié === "oui" ? PLAFOND_IMPOT_COUPLE_POUR_DECOTE : PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE;
  if ($impots < $plafondImpôtPourDécôte) {
    // максимальна сума знижки
    $plafondDécôte = $marié === "oui" ? PLAFOND_DECOTE_COUPLE : PLAFOND_DECOTE_CELIBATAIRE;
    // теоретична знижка
    $décôte = $plafondDé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 ceil($décôte);
}

Коментарі

  • рядок 6: максимальна сума валового податку, що дає право на знижку. Ця сума відрізняється для одиноких осіб та подружніх пар;
  • рядок 7: чи має платник податків право на знижку;
  • рядок 11: формула розрахунку знижки. [plafondDécôte] — це максимальна сума знижки. Ця максимальна сума розраховується у рядку 9. І тут вона залежить від сімейного стану платника податків — одруженого чи неодруженого;
  • рядки 13–15: знижка не може перевищувати суму валового податку до сплати. Це має місце, наприклад, якщо значення [impots] у рядку 11 дорівнює 0;
  • рядки 17–19: щоб уникнути округлення до -1;

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


// глобальні константи
define("PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION", 21037);
define("PLAFOND_REVENUS_COUPLE_POUR_REDUCTION", 42074);
define("VALEUR_REDUC_DEMI_PART", 3797);

// розраховує можливе зниження
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {
  // верхня межа доходу для отримання права на знижку у розмірі 20 %
  $plafondRevenuPourRéduction = $marié === "oui" ? PLAFOND_REVENUS_COUPLE_POUR_REDUCTION : PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION;
  $plafondRevenuPourRéduction += $enfants * VALEUR_REDUC_DEMI_PART;
  if ($enfants > 2) {
    $plafondRevenuPourRéduction += ($enfants - 2) * VALEUR_REDUC_DEMI_PART;
  }
  // оподатковуваний дохід
  $revenuImposable = getRevenuImposable($salaire);
  // знижка
  $réduction = 0;
  if ($revenuImposable < $plafondRevenuPourRéduction) {
    // знижка у розмірі 20 %
    $réduction = 0.2 * $impots;
  }
  // результат
  return ceil($réduction);
}

Коментарі

  • рядки 4–10: щоб мати право на податкову знижку, оподатковуваний дохід (рядок 10) повинен бути меншим за граничну суму, розраховану в рядках 4–8;
  • рядки 13–16: якщо платник податків відповідає вимогам, він має право на податкову знижку в розмірі 20 % (рядок 15);

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

Файл даних 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

Файл 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}

Отримані результати відповідають результатам, отриманим за допомогою симулятора податкової служби.

4.3.3. Висновок

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

4.4. Версія 2

4.4.1. Зміни

У попередній версії дані, необхідні для розрахунку податку, були жорстко закодовані у вигляді констант і масивів. Цей метод не рекомендується. У новій версії ці дані винесені в окремий файл jSON:

Image

Вміст файлу [taxadmindata.json] такий:


{
    "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],
    "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
}

Нова версія [version-02/main.php] виглядає так:


<?php

// суворе дотримання заявлених типів параметрів функцій
declare (strict_types=1);

// визначення констант
$TAXPAYERSDATA = "taxpayersdata.txt";
$RESULTATS = "resultats.txt";
$TAXADMINDATA = "taxadmindata.json";

// отримано вміст файлу податкових даних
$fileContents = \file_get_contents($TAXADMINDATA);
$erreur = FALSE;
// помилка?
if (!$fileContents) {
  // фіксуємо помилку
  $erreur = TRUE;
  $message = "Le fichier des données [$TAXADMINDATA] n'existe pas";
}

if (!$erreur) {
  // завантажуємо код jSON з конфігураційного файлу в асоціативний масив
  $taxAdminData = \json_decode($fileContents, true);
  // помилка?
  if (!$taxAdminData) {
    // зафіксовано помилку
    $erreur = TRUE;
    $message = "Le fichier de données jSON [$TAXADMINDATA] n'a pu être exploité correctement";
  }
}

// помилка?
if ($erreur) {
  print "$message\n";
  exit;
}

// відкриття файлу результатів
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
  print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
  // вивід
  exit;
}

// відкриття файлу даних платників податків
$taxpayersdata = fopen($TAXPAYERSDATA, "r");
if (!$taxpayersdata) {
  print "Impossible d'ouvrir le fichier des contribuables [$TAXPAYERSDATA]\n";
  // вихід
  exit;
}

// обробка поточного рядка файлу даних
while ($ligne = fgets($taxpayersdata, 100)) {
  // видалення можливого позначення кінця рядка
  $ligne = cutNewLineChar($ligne);
  // витягуються 3 поля «одружений:діти:зарплата», що утворюють $ligne
  list($marié, $enfants, $salaire) = explode(",", $ligne);
  // розраховується податок
  $result = calculImpot($taxAdminData, $marié, (int) $enfants, (int) $salaire);
  // записуємо результат у файл результатів
  $result = ["marié" => $marié, "enfants" => $enfants, "salaire" => $salaire] + $result;
  fputs($résultats, \json_encode($result, JSON_UNESCAPED_UNICODE) . "\n");
  // наступні дані
}
// закриваємо файли
fclose($taxpayersdata);
fclose($résultats);

// кінець
exit;

// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne) {

  // кінець
  return($ligne);
}

// розрахунок податку
// --------------------------------------------------------------------------
function calculImpot(array $taxAdminData, string $marié, int $enfants, float $salaire) {
  // $marié: так, ні
  // $enfants: кількість дітей
  // $salaire: річний оклад
  // $taxAdminData: дані податкової служби
  //
  // розрахунок податку з урахуванням дітей
  $result1 = calculImpot2($taxAdminData, $marié, $enfants, $salaire);
  $impot1 = $result1["impôt"];
  // розрахунок податку без урахування дітей
  if ($enfants != 0) {
    $result2 = calculImpot2($taxAdminData, $marié, 0, $salaire);
    $impot2 = $result2["impôt"];
    // застосування обмеження сімейного коефіцієнта
    if ($enfants < 3) {
      // $PLAFOND_QF_DEMI_PART євро за перших двох дітей
      $impot2 = $impot2 - $enfants * $taxAdminData["PLAFOND_QF_DEMI_PART"];
    } else {
      // $PLAFOND_QF_DEMI_PART євро за перших двох дітей, удвічі більше за наступних
      $impot2 = $impot2 - 2 * $taxAdminData["PLAFOND_QF_DEMI_PART"] - ($enfants - 2) * 2 * $taxAdminData["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 = getDecote($taxAdminData, $marié, $salaire, $impot);
  $impot -= $décôte;
  // розрахунок можливого зменшення податку
  $réduction = getRéduction($taxAdminData, $marié, $salaire, $enfants, $impot);
  $impot -= $réduction;
  // результат
  return ["impôt" => floor($impot), "surcôte" => $surcôte, "décôte" => $décôte, "réduction" => $réduction, "taux" => $taux];
}

// --------------------------------------------------------------------------
function calculImpot2(array $taxAdminData, string $marié, int $enfants, float $salaire) {
  // $marié: так, ні

  // результат
  return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}

// revenuImposable=річний-заробіток-пільга
// податкова пільга має мінімальний та максимальний розмір
function getRevenuImposable(array $taxAdminData, float $salaire): float {

  // результат
  return floor($revenuImposable);
}

// розраховує можливе зниження
function getDecote(array $taxAdminData, string $marié, float $salaire, float $impots): float {

  // результат
  return ceil($décôte);
}

// розраховує можливе зниження
function getRéduction(array $taxAdminData, string $marié, float $salaire, int $enfants, float $impots): float {

  // результат
  return ceil($réduction);
}

Коментарі

  • рядки 11–19: робиться спроба прочитати вміст файлу jSON, який має назву [TAXADMINDATA];
  • рядки 21–30: якщо вдалося прочитати файл jSON, його вміст декодується в асоціативний масив [$taxAdminData];
  • рядки 32–36: якщо під час виконання однієї з двох попередніх операцій сталася помилка, на консоль виводиться повідомлення про помилку, і програма зупиняється;
  • відмінність від версії 01 полягає в тому, що тут дані (масиви та константи) податкової адміністрації містяться в асоціативному масиві [$taxAdminData], тоді як у версії 01 вони були в глобальних масивах та константах. Саме глобальність цих констант і є відмінністю між двома версіями:
    • у версії 01 константи були відомі у всіх функціях масиву [main.php];
    • щоб отримати той самий результат у версії 02, потрібно передавати асоціативний масив [$taxAdminData] як параметр усім функціям (рядки 83, 129, 138, 145, 152);
  • кожна функція версії 02 повинна використовувати вміст масиву [$taxAdminData];
  • рядки 83–126: у функції [calculerImpot] там, де раніше використовувалися глобальні константи або масиви [limites, coeffR, coeffN], тепер використовується вміст масиву [$taxAdminData], отриманого як параметр (рядки 99, 102);
  • усі інші функції переписано аналогічним чином;

Отримані результати збігаються з результатами попередньої версії.

4.4.2. Висновок

Версія 02 є набагато гнучкішою, ніж версія 01. У 2020 році алгоритм розрахунку податку, ймовірно, буде таким самим, як і в 2019 році. Зміняться лише податкові шкали та константи розрахунку. Тоді достатньо буде лише оновити файл [taxadmindata.json]. У версії 01 потрібно зайти в код і змінити податкові шкали та константи розрахунку. Однак, ймовірно, що особи, яким доводиться змінювати значення податкових шкал та констант розрахунку, не мають доступу до коду алгоритму.