Skip to content

4. Ćwiczenie praktyczne – IMPOTS

4.1. Zadanie

Zadaniem jest napisanie programu umożliwiającego obliczenie podatku podatnika. Rozważamy uproszczony przypadek podatnika, który ma do zadeklarowania wyłącznie swoje wynagrodzenie:

  • liczy się liczbę udziałów pracownika według wzoru nbParts = nbEnfants/2 + 1, jeśli nie jest żonaty, nbEnfants/2+2, jeśli jest żonaty, gdzie nbEnfants to liczba jego dzieci.
  • Następnie oblicza się jego dochód podlegający opodatkowaniu R = 0,72 * S, gdzie S to jego roczne wynagrodzenie
  • oblicza się jego współczynnik rodzinny Q = R/N

oblicza się jego podatek I na podstawie następujących danych

12620,0
0
0
13 190
0,05
631
15640
0,1
1290,5
24 740
0,15
2072,5
31810
0,2
3309,5
39 970
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
172 040
0,55
30710
195 000
0,60
39312
0
0,65
49062

Każdy wiersz zawiera 3 pola. Aby obliczyć podatek I, należy znaleźć pierwszy wiersz, w którym QF <= pole1. Na przykład, jeśli QF = 30000, znajdziemy wiersz

    24740        0.15        2072.5

Podatek I wynosi wówczas 0,15*R – 2072,5*nbParts. Jeśli QF jest takie, że relacja QF <= pole1 nigdy nie jest spełniona, wówczas stosuje się współczynniki z ostatniego wiersza. W tym przypadku:

    0                0.65        49062

co daje podatek I = 0,65*R – 49062*nbParts.

4.2. Wersja z tabelami (impots_01)

Przedstawiamy pierwszy program, w którym:

  • dane niezbędne do obliczenia podatku znajdują się w trzech tabelach (limity, coeffR, coeffN)
  • dane podatników (stan cywilny, dzieci, wynagrodzenie) znajdują się w pierwszym pliku tekstowym
  • wyniki obliczeń podatku (stan cywilny, dzieci, wynagrodzenie, podatek) są zapisane w drugim pliku tekstowym

<?php

// definicja stałych
$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);

// odczyt danych
$data = fopen($DATA, "r");
if (!$data) {
  print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
  exit;
}

// otwarcie pliku wyników
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
  print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
  exit;
}

// przetwarzanie bieżącego wiersza pliku danych
while ($ligne = fgets($data, 100)) {
  // usuwanie ewentualnego znaku końca linii
  $ligne = cutNewLineChar($ligne);
  // pobierane są 3 pola: „marié”, „enfants” i „salaire”, które tworzą $ligne
  list($marié, $enfants, $salaire) = explode(",", $ligne);
  // oblicza się podatek
  $impôt = calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
  // wynik zapisuje się w pliku wyników
  fputs($résultats, "$marié:$enfants:$salaire:$impôt\n");
  // kolejny podatnik
}
// zamykamy pliki
fclose($data);
fclose($résultats);

// koniec
exit;

// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // usuwa się znak końca linii z $ligne, jeśli istnieje
  $L = strlen($ligne);  // długość wiersza
  while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
    $ligne = substr($ligne, 0, $L - 1);
    $L--;
  }
  // koniec
  return($ligne);
}

// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié: tak, nie
  // $enfants: liczba dzieci
  // $salaire: roczne wynagrodzenie
  // $limites, $coeffR, $coeffN: tabele danych umożliwiające obliczenie podatku
  
  // liczba udziałów
  $marié = strtolower($marié);
  if ($marié == "oui")
    $nbParts = $enfants / 2 + 2;
  else
    $nbParts=$enfants / 2 + 1;
  // dodatkowa połowa udziału, jeśli jest co najmniej troje dzieci
  if ($enfants >= 3)
    $nbParts+=0.5;
  // dochód podlegający opodatkowaniu
  $revenuImposable = 0.72 * $salaire;
  // współczynnik rodzinny
  $quotient = $revenuImposable / $nbParts;
  // jest umieszczany na końcu tabeli limitów w celu zakończenia następującej pętli
  array_push($limites, $quotient);
  // obliczenie podatku
  $i = 0;
  while ($quotient > $limites[$i])
    $i++;
  // ponieważ umieszczono $quotient na końcu tablicy $limites, poprzednia pętla
  // nie może wykraczać poza tablicę $limites
  // teraz można obliczyć podatek
  return floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
}
?>

Plik danych data.txt (stan cywilny, dzieci, wynagrodzenie):

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

Pliki résultats.txt (stan cywilny, dzieci, wynagrodzenie, podatek) zawierające uzyskane wyniki:

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

Uwagi

  • wiersz 4: nazwa pliku tekstowego zawierającego dane podatników (stan cywilny, dzieci, wynagrodzenie)
  • wiersz 5: nazwa pliku tekstowego zawierającego wyniki (stan cywilny, dzieci, wynagrodzenie, podatek) obliczeń podatku
  • wiersze 6–8: trzy tabele danych umożliwiające obliczenie podatku
  • wiersze 11–15: otwarcie pliku z danymi podatników w trybie odczytu
  • wiersze 18–22: otwarcie pliku wyników w trybie zapisu
  • wiersz 25: pętla odczytu wierszy (stan cywilny, liczba dzieci, wynagrodzenie) z pliku podatników
  • wiersz 27: znak końca wiersza zostaje usunięty
  • wiersz 29: pobierane są składniki (stan cywilny, dzieci, wynagrodzenie) z danego wiersza
  • wiersz 31: obliczany jest podatek
  • wiersz 33: podatek jest zapisywany w pliku wyników
  • wiersze 37–38: po pełnym przetworzeniu pliku podatników pliki są zamykane
  • wiersz 44: funkcja usuwająca znak końca wiersza z wiersza $ligne. Znakiem końca wiersza jest ciąg „\r\n” w systemach Windows oraz „\n” w systemach Unix. Wynikiem jest ciąg wejściowy bez znaku końca wiersza.
  • wiersze 47–48: substr($chaîne,$début,$taille) to podciąg ciągu $chaîne, zaczynający się od znaku $début i zawierający co najwyżej $taille znaków.
  • wiersz 63: funkcja strtolower($chaîne) zamienia $chaîne na małe litery
  • wiersz 76: array_push($tableau,$élément) dodaje $élément na końcu tablicy $tableau. Należy zauważyć, że tablica $limites została przekazana jako wartość do funkcji calculerImpot (wiersz 56: )). Dodanie tego elementu odbywa się zatem na kopii rzeczywistego parametru, który pozostaje niezmieniony.
  • wiersz 84: funkcja floor($x) zwraca wartość całkowitą bezpośrednio mniejszą od $x.

4.3. Wersja z plikami tekstowymi (impots_02)

Ta nowa wersja różni się od poprzedniej jedynie tym, że dane ($limites, $coeffR, $coeffN) niezbędne do obliczenia podatku znajdują się teraz w pliku tekstowym w następującej postaci:

Plik 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

Nowa wersja ogranicza się do odczytania danych z pliku [impots.txt] w celu umieszczenia ich w trzech tabelach ($limites, $coeffR, $coeffN). W ten sposób powracamy do poprzedniego przypadku. Przedstawiamy jedynie zmiany:


<?php

// definicja stałych
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$IMPOTS = "impots.txt";

// dane niezbędne do obliczenia podatku zostały umieszczone w pliku $IMPOTS
// po jednym wierszu na tabelę w postaci
// val1:val2:val3,...
list($erreur, $limites, $coeffR, $coeffN) = getTables($IMPOTS);

// czy wystąpił błąd?
if ($erreur) {
  print "$erreur\n";
  exit;
}//if
// odczyt danych użytkownika
...

// koniec
exit;

// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // usuwa się znacznik końca linii z $ligne, jeśli istnieje
...
}

// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié: tak, nie
  // $enfants: liczba dzieci
  // $salaire: roczne wynagrodzenie
  // $limites, $coeffR, $coeffN: tabele danych umożliwiające obliczenie podatku
  ...
}

// --------------------------------------------------------------------------
function getTables($IMPOTS) {
  // $IMPOTS: nazwa pliku zawierającego dane z tabel $limites, $coeffR, $coeffN
  // czy plik $IMPOTS istnieje?
  if (!file_exists($IMPOTS))
    return array("Le fichier $IMPOTS n'existe pas","","","");
  // odczyt pliku w bloku
  $tables = file($IMPOTS);
  if (!$tables)
    return array("Erreur lors de l'exploitation du fichier $IMPOTS","","","");
  // utworzenie 3 tabel – zakłada się, że wiersze są poprawne pod względem składniowym
  $limites = explode(":", cutNewLineChar($tables[0]));
  $coeffR = explode(":", cutNewLineChar($tables[1]));
  $coeffN = explode(":", cutNewLineChar($tables[2]));
  // koniec
  return array("", $limites, $coeffR, $coeffN);
}
?>

Komentarze

  • wiersz 11: funkcja getTables($IMPOTS) przetwarza plik tekstowy $IMPOTS w celu wyodrębnienia z niego trzech tablic ($limites, $coeffR, $coeffN). Wynikiem są ($erreur, $limites, $coeffR, $coeffN), gdzie $erreur to komunikat o błędzie, pusty, jeśli nie wystąpił żaden błąd.
  • wiersz 40: funkcja getTables($IMPOTS).
  • wiersz 43: funkcja files_exists(nom_fichier) zwraca wartość logiczną true, jeśli plik nom_fichier istnieje, w przeciwnym razie zwraca wartość logiczną false.
  • wiersz 46: funkcja file(nom_fichier) odczytuje cały plik tekstowy nom_fichier. Zwraca tablicę, w której każdy element stanowi wiersz pliku tekstowego. Ponieważ w tym przypadku plik impots.txt zawiera trzy wiersze tekstu, funkcja zwróci tablicę składającą się z trzech elementów.
  • wiersze 50–52: wykorzystanie trzech pobranych wierszy do utworzenia trzech tablic ($limites, $coeffR, $coeffN)

Uzyskane wyniki są takie same jak w poprzedniej wersji.