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

Наведена вище таблиця дозволяє розрахувати податок у спрощеному випадку, коли платник податків декларує лише свою заробітну плату. Як зазначено у примітці (1), розрахований таким чином податок є податком до застосування трьох механізмів:
- обмеження сімейного коефіцієнта, яке застосовується до високих доходів;
- знижки та зменшення податку, що застосовуються до низьких доходів;
Отже, розрахунок податку включає такі етапи [http://impotsurlerevenu.org/comprendre-le-calcul-de-l-impot/1217-calcul-de-l-impot-2019.php]:

Пропонується написати програму, яка дозволить розрахувати податок платника податків у спрощеному випадку, коли платник податків має лише одну заробітну плату, яку потрібно задекларувати:
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, виглядає так:
Тоді податок I дорівнює 0,14*R – 1394,96*nbParts=[0,14*45000-1394,96*3]=2115. Податок округлюється до найближчого нижчого євро.
Якщо вже в першому рядку виконується умова QF <= поле1, то податок дорівнює нулю.
Якщо QF таке, що умова QF<=поле1 ніколи не виконується, то використовуються коефіцієнти останнього рядка. У даному випадку:
що дає валовий податок I = 0,45*R – 20163,45*nbParts.
4.1.2. Обмеження сімейного коефіцієнта

Щоб з’ясувати, чи застосовується обмеження сімейного коефіцієнта QF, потрібно перерахувати валовий податок без урахування дітей. Знову ж таки, для працівника, який перебуває у шлюбі, має двох дітей та отримує річну заробітну плату S у розмірі 50000 євро:
Оподатковуваний дохід: R = 0,9 * S = 45 000
Кількість часток: nbParts=2 (дітей більше не враховують)
Сімейний коефіцієнт: QF=45000/2=22500
Перший рядок, у якому QF <= поле1, має такий вигляд:
Тоді податок 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. Розрахунок знижки

Знову ж таки, для працівника, який перебуває у шлюбі, має двох дітей та отримує річну заробітну плату S у розмірі 50000 євро:
Валовий податок (2115), отриманий на попередньому етапі, є меншим за 2627 євро для подружжя (1595 євро для одинокої особи): отже, застосовується знижка. Її розраховують за такою формулою:
знижка = поріг (для подружжя = 1970 / для одинокої особи = 1196) – 0,75 * валовий податок
знижка = 1970 – 0,75 × 2115 = 383,75, округлено до 384 євро.
Новий валовий податок = 2115 – 384 = 1731 євро
4.1.4. Розрахунок податкової знижки

Нижче певного порогу до валового податку, розрахованого за попередніми розрахунками, застосовується знижка у розмірі 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. Структура скриптів

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 (одружений, діти, заробітна плата):
Файл résultats.txt (сімейний стан, діти, заробітна плата, податок, надбавка, знижка, зменшення, ставка оподаткування) з отриманими результатами:
Коментарі
- рядок 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 (одружений, діти, заробітна плата):
Файл résultats.txt (сімейний стан, діти, заробітна плата, податок, надбавка, знижка, зменшення, ставка оподаткування) з отриманими результатами:
Отримані результати відповідають результатам, отриманим за допомогою симулятора податкової служби.
4.3.3. Висновок
Алгоритм розрахунку податку, навіть у випадках, що вважаються простими, є складним. Ми більше не будемо на цьому зупинятися. У наступних версіях його основа залишиться незмінною, незважаючи на деякі зміни у форматі подання. Тому ми коментуватимемо лише останні.
4.4. Версія 2
4.4.1. Зміни
У попередній версії дані, необхідні для розрахунку податку, були жорстко закодовані у вигляді констант і масивів. Цей метод не рекомендується. У новій версії ці дані винесені в окремий файл jSON:

Вміст файлу [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 потрібно зайти в код і змінити податкові шкали та константи розрахунку. Однак, ймовірно, що особи, яким доводиться змінювати значення податкових шкал та констант розрахунку, не мають доступу до коду алгоритму.