Skip to content

4. Application Exercise - IMPOTS

4.1. The Problem

We aim to write a program to calculate a taxpayer’s tax. We consider the simplified case of a taxpayer who has only their salary to report:

  • we calculate the number of shares for the employee nbParts = nbEnfants/2 + 1 if they are unmarried, nbEnfants/2+2 if they are married, where nbEnfants is the number of children.
  • We calculate his taxable income R = 0.72 * S, where S is his annual salary
  • we calculate his family coefficient Q = R/N

we calculate his tax I based on the following data

12620.0
0
0
13,190
0.05
631
15,640
0.1
1,290.5
24,740
0.15
2,072.5
31,810
0.2
3,309.5
39,970
0.25
4,900
48,360
0.3
6898.5
55,790
0.35
9,316.5
92,970
0.4
12,106
127,860
0.45
16,754.5
151,250
0.50
23,147.5
172,040
0.55
30,710
195,000
0.60
39,312
0
0.65
49,062

Each row has 3 fields. To calculate tax I, we look for the first row where QF <= field1. For example, if QF = 30000, we will find the row

    24740        0.15        2072.5

Tax I is then equal to 0.15*R - 2072.5*nbParts. If QF is such that the relation QF <= field1 is never satisfied, then the coefficients from the last row are used. Here:

    0                0.65        49062

which gives the tax I=0.65*R – 49062*nbParts.

4.2. Version with tables (impots_01)

We present an initial program where:

  • the data needed to calculate the tax are in three tables (limits, coeffR, coeffN)
  • the taxpayer data (married, children, salary) is in a first text file
  • the results of the tax calculation (married, children, salary, tax) are stored in a second text file

<?php
 
// definition of constants
$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);
 
// reading data
$data = fopen($DATA, "r");
if (!$data) {
  print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
  exit;
}
 
// open results file
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
  print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
  exit;
}
 
// use the current line of the data file
while ($ligne = fgets($data, 100)) {
  // remove any end-of-line marker
  $ligne = cutNewLineChar($ligne);
  // we retrieve the 3 fields married,children,salary which form $ligne
  list($marié, $enfants, $salaire) = explode(",", $ligne);
  // tax calculation
  $impôt = calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
  // enter the result in the results file
  fputs($résultats, "$marié:$enfants:$salaire:$impôt\n");
  // next taxpayer
}
// close files
fclose($data);
fclose($résultats);
 
// end
exit;
 
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // delete the end-of-line mark from $ligne if it exists
  $L = strlen($ligne);  // line length
  while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
    $ligne = substr($ligne, 0, $L - 1);
    $L--;
  }
  // end
  return($ligne);
}
 
// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié : yes, no
  // $enfants : number of children
  // $salaire: annual salary
  // $limites, $coeffR, $coeffN: tax calculation data tables
 
  // number of shares
  $marié = strtolower($marié);
  if ($marié == "oui")
    $nbParts = $enfants / 2 + 2;
  else
    $nbParts=$enfants / 2 + 1;
  // an additional 1/2 share if at least 3 children
  if ($enfants >= 3)
    $nbParts+=0.5;
  // taxable income
  $revenuImposable = 0.72 * $salaire;
  // family quotient
  $quotient = $revenuImposable / $nbParts;
  // is set at the end of the limit table to stop the following loop
  array_push($limites, $quotient);
  // tAX CALCULATION
  $i = 0;
  while ($quotient > $limites[$i])
    $i++;
  // because $quotient has been placed at the end of the $limites array, the previous loop
  // cannot exceed the table $limites
  // now we can calculate the tax
  return floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
}
?>

The data.txt data file (married, children, salary):

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

The résultats.txt file (married, children, salary, tax) of the results obtained:

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

Comments

  • line 4: the name of the text file containing taxpayer data (married, children, salary)
  • line 5: the name of the text file containing the results (married, children, salary, tax) of the tax calculation
  • lines 6–8: the three data tables used to calculate the tax
  • lines 11-15: open the taxpayer data file for reading
  • lines 18–22: open the results file for writing
  • line 25: loop to read the lines (married, children, salary) from the taxpayer file
  • line 27: the end-of-line marker is removed
  • line 29: the components (married, children, salary) of the line are retrieved
  • line 31: tax is calculated
  • line 33: the tax is stored in the results file
  • lines 37-38: once the taxpayer file has been fully processed, the files are closed
  • line 44: the function that removes the end-of-line character from a line $ligne. The end-of-line character is the string "\r\n" on Windows systems, "\n" on Unix systems. The result is the input string without its end-of-line character.
  • lines 47–48: substr($chaîne,$début,$taille) is the substring of $chaîne starting at the character $début and having at most $taille characters.
  • line 63: strtolower($chaîne) converts $chaîne to lowercase
  • line 76: array_push($tableau,$élément) adds $élément to the end of the array $tableau. Note that the array $limites is passed by value to the function calculerImpot (line 56). This addition of an element is therefore performed on the copy of the actual parameter, which remains unchanged.
  • Line 84: The function floor($x) returns the integer value immediately less than $x.

4.3. Version with text files (impots_02)

This new version differs from the previous one only in that the data ($limites, $coeffR, $coeffN) required for tax calculation are now in a text file in the following format:

File 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

The new version simply reads the data from the [impots.txt] file in order to place it into three tables ($limites, $coeffR, $coeffN). This brings us back to the previous case. We will only present the changes:


<?php
 
// definition of constants
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$IMPOTS = "impots.txt";
 
// the data required to calculate the tax has been placed in the $IMPOTS file
// one line per table in the form
// val1:val2:val3,...
list($erreur, $limites, $coeffR, $coeffN) = getTables($IMPOTS);
 
// was there a mistake?
if ($erreur) {
  print "$erreur\n";
  exit;
}//if
// reading user data
...
 
// end
exit;
 
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // delete the end-of-line mark from $ligne if it exists
...
}
 
// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié : yes, no
  // $enfants : number of children
  // $salaire: annual salary
  // $limites, $coeffR, $coeffN: tax calculation data tables
  ...
}
 
// --------------------------------------------------------------------------
function getTables($IMPOTS) {
  // $IMPOTS: name of the file containing data from tables $limites, $coeffR, $coeffN
  // does the $IMPOTS file exist?
  if (!file_exists($IMPOTS))
    return array("Le fichier $IMPOTS n'existe pas","","","");
  // file block playback
  $tables = file($IMPOTS);
  if (!$tables)
    return array("Erreur lors de l'exploitation du fichier $IMPOTS","","","");
  // create the 3 tables - assume the rows are syntactically correct
  $limites = explode(":", cutNewLineChar($tables[0]));
  $coeffR = explode(":", cutNewLineChar($tables[1]));
  $coeffN = explode(":", cutNewLineChar($tables[2]));
  // end
  return array("", $limites, $coeffR, $coeffN);
}
?>

Comments

  • line 11: the function getTables($IMPOTS) processes the text file $IMPOTS to extract the three arrays ($limites, $coeffR, $coeffN). The result returned is ($erreur, $limites, $coeffR, $coeffN), where $erreur is an error message, empty if no error occurred.
  • line 40: the function getTables($IMPOTS).
  • line 43: the function files_exists(nom_fichier) returns true if the file nom_fichier exists, false otherwise.
  • Line 46: The function file(nom_fichier) reads the entire text file nom_fichier. It returns an array where each element is a line of the text file. Since, in this case, the file impots.txt has three lines of text, the function will return an array with three elements.
  • Lines 50–52: Use the three retrieved lines to create the three arrays ($limites, $coeffR, $coeffN)

The results obtained are the same as those obtained in the previous version.