4. Ejercicio de aplicación - IMPOTS
4.1. El problema
Nos proponemos escribir un programa que permita calcular los impuestos de un contribuyente. Nos situamos en 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 renta imponible R = 0,72 * S, donde S es su salario anual
- se calcula su coeficiente familiar Q = R/N
se calcula su impuesto I a partir de 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 | 16754,5 |
151 250 | 0,50 | 231 47,5 |
172 040 | 0,55 | 30710 |
195 000 | 0,60 | 39312 |
0 | 0,65 | 49062 |
Cada línea tiene 3 campos. Para calcular el impuesto I, se busca la primera línea donde QF<=campo1. Por ejemplo, si QF=30000, se encontrará la línea
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:
lo que da el impuesto I=0,65*R – 49062*nbParts.
4.2. Version con tablas (impots_01)
Presentamos un primer programa en el que:
- los datos necesarios para el cálculo del 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 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 introduce 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 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: tablas de datos que permiten el cálculo del impuesto
// número de participaciones
$marié = strtolower($marié);
if ($marié == "oui")
$nbParts = $enfants / 2 + 2;
else
$nbParts=$enfants / 2 + 1;
// una participación y media más si hay al menos tres hijos
if ($enfants >= 3)
$nbParts+=0.5;
// renta imponible
$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 ha colocado $quotient al final de la tabla $limites, el bucle anterior
// no puede salirse 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):
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 el cálculo del impuesto
- líneas 11-15: apertura en modo 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 almacena en el archivo de resultados
- líneas 37-38: una vez procesado completamente 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) añade $é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 elementos se realiza sobre la copia del parámetro efectivo, que permanece inalterado.
- línea 84: la función floor($x) devuelve el valor entero inmediatamente inferior a $x.
4.3. Version con archivos de texto (impots_02)
Esta nueva version 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
El nuevo version se limita a leer los datos del archivo [impots.txt] para colocarlos en tres tablas ($limites, $coeffR, $coeffN). Así que volvemos 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);
// ¿Se ha producido algún error?
if ($erreur) {
print "$erreur\n";
exit;
}//if
// lectura de los datos de usuario
...
// fin
exit;
// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
// se elimina la marca 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: tablas de datos que permiten el cálculo del 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, vacío si no se ha producido 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, y false en caso contrario.
- 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 las tres matrices ($limites, $coeffR, $coeffN)
Los resultados obtenidos son los mismos que los obtenidos en el version anterior.