Skip to content

4. Ejercicio de aplicación - IMPOTS

4.1. El problema

Nos proponemos escribir un programa que permita calcular el impuesto de un contribuyente. Consideramos el caso simplificado de un contribuyente que solo tiene que declarar su salario:

  • Se calcula el número de partes del empleado nbParts = nbEnfants/2 + 1 si no está casado, nbEnfants/2 + 2 si está casado, donde nbEnfants es su número de hijos.
  • se calcula su ingreso imponible R = 0,72 * S, donde S es su salario anual
  • se calcula su coeficiente familiar Q = R/N

se calcula su impuesto I según los siguientes datos

12620.0
0
0
13 190
0,05
631
15640
0,1
1290,5
24 740
0,15
2072,5
31 810
0,2
3309,5
39 970
0,25
4900
48 360
0,3
6898,5
55 790
0,35
9316,5
92 970
0,4
12106
127 860
0,45
16 754,5
151 250
0,50
23 147,5
172 040
0,55
30 710
195 000
0,60
39312
0
0,65
49 062

Cada línea tiene 3 campos. Para calcular el impuesto I, se busca la primera línea en la que QF sea menor o igual que el campo 1. Por ejemplo, si QF = 30000, se encontrará la línea

    24740        0.15        2072.5

El impuesto I es entonces igual a 0,15*R - 2072,5*nbParts. Si QF es tal que la relación QF <= campo1 nunca se cumple, entonces se utilizan los coeficientes de la última línea. En este caso:

    0                0.65        49062

lo que da como resultado el impuesto I = 0,65 * R – 49 062 * nbParts.

4.2. Versión con tablas (impots_01)

Presentamos un primer programa en el que:

  • los datos necesarios para calcular el impuesto se encuentran en tres tablas (límites, coeffR, coeffN)
  • los datos de los contribuyentes (estado civil, hijos, salario) se encuentran en un primer archivo de texto
  • los resultados del cálculo del impuesto (estado civil, hijos, salario, impuesto) se almacenan en un segundo archivo de texto

<?php

// definición de las constantes
$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);

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

// apertura del archivo de resultados
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
  print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
  exit;
}

// se procesa la línea actual del archivo de datos
while ($ligne = fgets($data, 100)) {
  // se elimina el posible carácter de fin de línea
  $ligne = cutNewLineChar($ligne);
  // se recuperan los 3 campos «casado», «hijos» y «salario» que forman $ligne
  list($marié, $enfants, $salaire) = explode(",", $ligne);
  // se calcula el impuesto
  $impôt = calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
  // se registra el resultado en el archivo de resultados
  fputs($résultats, "$marié:$enfants:$salaire:$impôt\n");
  // siguiente contribuyente
}
// se cierran los archivos
fclose($data);
fclose($résultats);

// fin
exit;

// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // se elimina el marcador de fin de línea de $ligne si existe
  $L = strlen($ligne);  // longitud de la línea
  while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
    $ligne = substr($ligne, 0, $L - 1);
    $L--;
  }
  // fin
  return($ligne);
}

// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié: sí, no
  // $enfants: número de hijos
  // $salaire: salario anual
  // $limites, $coeffR, $coeffN: las tablas de datos que permiten calcular el impuesto
  
  // número de partes
  $marié = strtolower($marié);
  if ($marié == "oui")
    $nbParts = $enfants / 2 + 2;
  else
    $nbParts=$enfants / 2 + 1;
  // media participación adicional si hay al menos tres hijos
  if ($enfants >= 3)
    $nbParts+=0.5;
  // ingresos imponibles
  $revenuImposable = 0.72 * $salaire;
  // coeficiente familiar
  $quotient = $revenuImposable / $nbParts;
  // se coloca al final de la tabla de límites para detener el bucle siguiente
  array_push($limites, $quotient);
  // cálculo del impuesto
  $i = 0;
  while ($quotient > $limites[$i])
    $i++;
  // debido a que se colocó $quotient al final de la tabla $limites, el bucle anterior
  // no puede salirse de los límites de la tabla $limites
  // ahora podemos calcular el impuesto
  return floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
}
?>

El archivo de datos data.txt (estado civil, hijos, salario):

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

Los archivos résultats.txt (estado civil, hijos, salario, impuestos) de los resultados obtenidos:

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

Comentarios

  • línea 4: el nombre del archivo de texto que contiene los datos de los contribuyentes (estado civil, hijos, salario)
  • línea 5: el nombre del archivo de texto que contiene los resultados (estado civil, hijos, salario, impuesto) del cálculo del impuesto
  • líneas 6-8: las tres tablas de datos que permiten calcular el impuesto
  • líneas 11-15: apertura en modo de lectura del archivo de datos de los contribuyentes
  • líneas 18-22: apertura en modo de escritura del archivo de resultados
  • línea 25: bucle de lectura de las líneas (estado civil, hijos, salario) del archivo de contribuyentes
  • línea 27: se elimina el marcador de fin de línea
  • línea 29: se recuperan los componentes (estado civil, hijos, salario) de la línea
  • línea 31: se calcula el impuesto
  • línea 33: el impuesto se guarda en el archivo de resultados
  • líneas 37-38: una vez que se ha procesado por completo el archivo de contribuyentes, se cierran los archivos
  • línea 44: la función que elimina el marcador de fin de línea de una línea $ligne. El marcador de fin de línea es la cadena "\r\n" en sistemas Windows y "\n" en sistemas Unix. El resultado es la cadena de entrada sin su marcador de fin de línea.
  • líneas 47-48: substr($chaîne,$début,$taille) es la subcadena de $chaîne que comienza en el carácter $début y tiene como máximo $taille caracteres.
  • línea 63: strtolower($chaîne) convierte $chaîne a minúsculas
  • línea 76: array_push($tableau,$élément) agrega $élément al final de la matriz $tableau. Cabe señalar que la matriz $limites se pasa por valor a la función calculerImpot (línea 56: )). Por lo tanto, esta adición de un elemento se realiza en la copia del parámetro efectivo, el cual permanece sin cambios.
  • línea 84: la función floor($x) devuelve el valor entero inmediatamente inferior a $x.

4.3. Versión con archivos de texto (impots_02)

Esta nueva versión solo se diferencia de la anterior en que los datos ($limites, $coeffR, $coeffN) necesarios para el cálculo del impuesto se encuentran ahora en un archivo de texto con el siguiente formato:

Archivo 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

La nueva versión simplemente lee los datos del archivo [impots.txt] para colocarlos en tres tablas ($limites, $coeffR, $coeffN). Esto nos lleva de nuevo al caso anterior. Solo presentamos los cambios:


<?php

// definición de las constantes
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$IMPOTS = "impots.txt";

// los datos necesarios para el cálculo del impuesto se han colocado en el archivo $IMPOTS
// a razón de una línea por tabla en el formato
// val1:val2:val3,...
list($erreur, $limites, $coeffR, $coeffN) = getTables($IMPOTS);

// ¿Ha ocurrido algún error?
if ($erreur) {
  print "$erreur\n";
  exit;
}//si
// lectura de los datos del usuario
...

// fin
exit;

// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // se elimina el marcador de fin de línea de $ligne si existe
...
}

// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié: sí, no
  // $enfants: número de hijos
  // $salaire: salario anual
  // $limites, $coeffR, $coeffN: las tablas de datos que permiten calcular el impuesto
  ...
}

// --------------------------------------------------------------------------
function getTables($IMPOTS) {
  // $IMPOTS: el nombre del archivo que contiene los datos de las tablas $limites, $coeffR, $coeffN
  // ¿Existe el archivo $IMPOTS?
  if (!file_exists($IMPOTS))
    return array("Le fichier $IMPOTS n'existe pas","","","");
  // lectura en bloque del archivo
  $tables = file($IMPOTS);
  if (!$tables)
    return array("Erreur lors de l'exploitation du fichier $IMPOTS","","","");
  // creación de las 3 tablas —se supone que las líneas son sintácticamente correctas
  $limites = explode(":", cutNewLineChar($tables[0]));
  $coeffR = explode(":", cutNewLineChar($tables[1]));
  $coeffN = explode(":", cutNewLineChar($tables[2]));
  // fin
  return array("", $limites, $coeffR, $coeffN);
}
?>

Comentarios

  • línea 11: la función getTables($IMPOTS) utiliza el archivo de texto $IMPOTS para extraer las tres tablas ($limites, $coeffR, $coeffN). El resultado obtenido es ($erreur, $limites, $coeffR, $coeffN), donde $erreur es un mensaje de error, que queda vacío si no hubo ningún error.
  • línea 40: la función getTables($IMPOTS).
  • línea 43: la función files_exists(nom_fichier) devuelve el valor booleano true si el archivo nom_fichier existe; de lo contrario, devuelve el valor booleano false.
  • línea 46: la función file(nom_fichier) lee todo el archivo de texto nom_fichier. Devuelve una matriz en la que cada elemento es una línea del archivo de texto. Como en este caso el archivo impots.txt tiene tres líneas de texto, la función devolverá una matriz de tres elementos.
  • líneas 50-52: uso de las tres líneas recuperadas para crear los tres arreglos ($limites, $coeffR, $coeffN)

Los resultados obtenidos son los mismos que en la versión anterior.