Skip to content

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

4.1. Задача

Задано написати програму, яка дозволяє обчислити податок платника податків. Розглянемо спрощений випадок, коли платник податків має задекларувати лише свою заробітну плату:

  • кількість часток працівника обчислюється за формулою nbParts = nbEnfants/2 + 1, якщо він не одружений, nbEnfants/2+2, якщо він одружений, де nbEnfants — кількість його дітей.
  • розраховується його оподатковуваний дохід R = 0,72 * S, де S — його річна заробітна плата
  • розраховується його сімейний коефіцієнт Q = R/N

розраховуємо його податок I на основі таких даних

12620,0
0
0
13190
0,05
631
15640
0,1
1290,5
24740
0,15
2072,5
31810
0,2
3309,5
39970
0,25
4900
48360
0,3
6898,5
55790
0,35
9316,5
92970
0,4
12106
127860
0,45
16754,5
151250
0,50
23147,5
172040
0,55
30710
195 000
0,60
39312
0
0,65
49062

Кожен рядок має 3 поля. Щоб обчислити податок I, шукаємо перший рядок, у якому QF <= поле1. Наприклад, якщо QF = 30000, то знайдемо рядок

    24740        0.15        2072.5

Тоді податок I дорівнює 0,15*R - 2072,5*nbParts. Якщо QF є таким, що співвідношення QF<=поле1 ніколи не виконується, то використовуються коефіцієнти останнього рядка. У даному випадку:

    0                0.65        49062

що дає податок I=0,65*R – 49062*nbParts.

4.2. Версія з таблицями (impots_01)

Ми пропонуємо першу програму, в якій:

  • дані, необхідні для розрахунку податку, містяться у трьох масивах (limites, coeffR, coeffN)
  • дані про платників податків (сімейний стан, діти, заробітна плата) містяться в першому текстовому файлі
  • результати розрахунку податку (сімейний стан, діти, заробітна плата, податок) зберігаються у другому текстовому файлі

<?php

// визначення констант
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$limites = array(12620, 13190, 15640, 24740, 31810, 39970, 48360, 55790, 92970, 127860, 151250, 172040, 195000);
$coeffR = array(0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65);
$coeffN = array(0, 631, 1290.5, 2072.5, 3309.5, 4900, 6898.5, 9316.5, 12106, 16754.5, 23147.5, 30710, 39312, 49062);

// читання даних
$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);
  // розраховується податок
  $impôt = calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
  // записуємо результат у файл результатів
  fputs($résultats, "$marié:$enfants:$salaire:$impôt\n");
  // наступний платник податків
}
// закриваємо файли
fclose($data);
fclose($résultats);

// кінець
exit;

// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // видаляється маркер кінця рядка з $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 calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié: так, ні
  // $enfants: кількість дітей
  // $salaire: річний оклад
  // $limites, $coeffR, $coeffN: таблиці даних, що дозволяють розрахувати податок
  
  // кількість часток
  $marié = strtolower($marié);
  if ($marié == "oui")
    $nbParts = $enfants / 2 + 2;
  else
    $nbParts=$enfants / 2 + 1;
  // на 1/2 частки більше, якщо є щонайменше 3 дітей
  if ($enfants >= 3)
    $nbParts+=0.5;
  // оподатковуваний дохід
  $revenuImposable = 0.72 * $salaire;
  // сімейний коефіцієнт
  $quotient = $revenuImposable / $nbParts;
  // вказується в кінці таблиці обмежень для припинення наступного циклу
  array_push($limites, $quotient);
  // розрахунок податку
  $i = 0;
  while ($quotient > $limites[$i])
    $i++;
  // оскільки $quotient розміщено в кінці таблиці $limites, попередній цикл
  // не може виходити за межі масиву $limites
  // тепер можна обчислити податок
  return floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
}
?>

Файл даних data.txt (статус шлюбу, діти, заробітна плата):

oui,2,200000
non,2,200000
oui,3,200000
non,3,200000
oui,5,50000
non,0,3000000

Файли résultats.txt (сімейний стан, діти, заробітна плата, податок) з отриманими результатами:

oui:2:200000:22504
non:2:200000:33388
oui:3:200000:16400
non:3:200000:22504
oui:5:50000:0
non:0:3000000:1354938

Коментарі

  • рядок 4: назва текстового файлу, що містить дані про платників податків (статус шлюбу, діти, заробітна плата)
  • рядок 5: ім’я текстового файлу, що містить результати (статус у шлюбі, діти, заробітна плата, податок) розрахунку податку
  • рядки 6–8: три таблиці даних, що дозволяють розрахувати податок
  • рядки 11–15: відкриття файлу з даними платників податків у режимі читання
  • рядки 18–22: відкриття файлу результатів для запису
  • рядок 25: цикл читання рядків (сімейний стан, діти, заробітна плата) з файлу даних про платників податків
  • рядок 27: видалення позначки кінця рядка
  • рядок 29: витягуються складові (статус одруженого, діти, заробітна плата) рядка
  • рядок 31: обчислюється податок
  • рядок 33: податок записується у файл результатів
  • рядки 37–38: після повного опрацювання файлу платників податків файли закриваються
  • рядок 44: функція, яка видаляє маркер кінця рядка з рядка $ligne. Маркером кінця рядка є рядок "\r\n" у системах Windows та "\n" у системах Unix. Результатом є вхідний рядок без маркера кінця рядка.
  • рядки 47–48: substr($chaîne,$début,$taille) — це підрядок рядка $chaîne, що починається з символу $début і містить не більше $taille символів.
  • рядок 63: strtolower($chaîne) перетворює $chaîne на малі літери
  • рядок 76: array_push($tableau,$élément) додає $élément у кінець масиву $tableau. Слід зауважити, що масив $limites передається за значенням у функцію calculerImpot (рядок 56)). Отже, додавання елемента відбувається до копії фактичного параметра, який залишається незмінним.
  • рядок 84: функція floor($x) повертає ціле значення, безпосередньо менше за $x.

4.3. Версія з текстовими файлами (impots_02)

Ця нова версія відрізняється від попередньої лише тим, що дані ($limites, $coeffR, $coeffN), необхідні для розрахунку податку, тепер містяться у текстовому файлі у такому вигляді:

Файл impots.txt:

12620:13190:15640:24740:31810:39970:48360:55790:92970:127860:151250:172040:195000:0
0:0.05:0.1:0.15:0.2:0.25:0.3:0.35:0.4:0.45:0.5:0.55:0.6:0.65
0:631:1290.5:2072.5:3309.5:4900:6898.5:9316.5:12106:16754.5:23147.5:30710:39312:49062

Нова версія просто зчитує дані з файлу [impots.txt], щоб помістити їх у три таблиці ($limites, $coeffR, $coeffN). Отже, ми повертаємося до попереднього випадку. Наводимо лише зміни:


<?php

// визначення констант
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$IMPOTS = "impots.txt";

// дані, необхідні для розрахунку податку, були розміщені у файлі $IMPOTS
// по одному рядку на таблицю у вигляді
// val1:val2:val3,...
list($erreur, $limites, $coeffR, $coeffN) = getTables($IMPOTS);

// Чи сталася помилка?
if ($erreur) {
  print "$erreur\n";
  exit;
}//if
// читання даних користувача
...

// кінець
exit;

// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // видаляємо маркер кінця рядка з $ligne, якщо він існує
...
}

// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié: так, ні
  // $enfants: кількість дітей
  // $salaire: річний оклад
  // $limites, $coeffR, $coeffN: таблиці даних, що дозволяють розрахувати податок
  ...
}

// --------------------------------------------------------------------------
function getTables($IMPOTS) {
  // $IMPOTS: назва файлу, що містить дані з таблиць $limites, $coeffR, $coeffN
  // чи існує файл $IMPOTS?
  if (!file_exists($IMPOTS))
    return array("Le fichier $IMPOTS n'existe pas","","","");
  // блокове читання файлу
  $tables = file($IMPOTS);
  if (!$tables)
    return array("Erreur lors de l'exploitation du fichier $IMPOTS","","","");
  // створення 3 таблиць — припускаємо, що рядки синтаксично правильні
  $limites = explode(":", cutNewLineChar($tables[0]));
  $coeffR = explode(":", cutNewLineChar($tables[1]));
  $coeffN = explode(":", cutNewLineChar($tables[2]));
  // кінець
  return array("", $limites, $coeffR, $coeffN);
}
?>

Коментарі

  • рядок 11: функція getTables($IMPOTS) обробляє текстовий файл $IMPOTS, щоб витягти з нього три масиви ($limites, $coeffR, $coeffN). Результат, що повертається, — це ($erreur, $limites, $coeffR, $coeffN), де $erreur — це повідомлення про помилку, яке залишається порожнім, якщо помилки не сталося.
  • рядок 40: функція getTables($IMPOTS).
  • рядок 43: функція files_exists(nom_fichier) повертає логічне значення true, якщо файл nom_fichier існує, і логічне значення false — у протилежному випадку.
  • рядок 46: функція file(nom_fichier) зчитує весь текстовий файл nom_fichier. Вона повертає масив, кожен елемент якого є рядком текстового файлу. Оскільки в даному випадку файл impots.txt містить три рядки тексту, функція поверне масив із трьома елементами.
  • рядки 50–52: використання трьох отриманих рядків для створення трьох масивів ($limites, $coeffR, $coeffN)

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