Skip to content

4. Exercício prático - IMPOTS

4.1. O problema

Propõe-se escrever um programa que permita calcular o imposto de um contribuinte. Consideramos o caso simplificado de um contribuinte que tenha apenas o seu salário para declarar:

  • calcula-se o número de quotas do trabalhador nbParts = nbEnfants/2 + 1 se não for casado, nbEnfants/2 + 2 se for casado, em que nbEnfants é o número de filhos que tem.
  • calcula-se o seu rendimento tributável R = 0,72 * S, em que S é o seu salário anual
  • calcula-se o seu coeficiente familiar Q = R/N

calcula-se o seu imposto I com base nos seguintes dados

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
30710
195 000
0,60
39312
0
0,65
49062

Cada linha tem 3 campos. Para calcular o imposto I, procura-se a primeira linha em que QF <= campo1. Por exemplo, se QF = 30000, encontrar-se-á a linha

    24740        0.15        2072.5

O imposto I é, então, igual a 0,15*R - 2072,5*nbParts. Se QF for tal que a relação QF <= campo1 nunca for verificada, então são utilizados os coeficientes da última linha. Neste caso:

    0                0.65        49062

o que resulta no imposto I = 0,65*R – 49062*nbParts.

4.2. Versão com tabelas (impots_01)

Apresentamos um primeiro programa em que:

  • os dados necessários para o cálculo do imposto estão em três tabelas (limites, coeffR, coeffN)
  • os dados dos contribuintes (casado, filhos, salário) encontram-se num primeiro ficheiro de texto
  • os resultados do cálculo do imposto (estado civil, filhos, salário, imposto) são guardados num segundo ficheiro de texto

<?php

// definição das 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);

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

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

// processa-se a linha atual do ficheiro de dados
while ($ligne = fgets($data, 100)) {
  // remove-se o eventual caractere de fim de linha
  $ligne = cutNewLineChar($ligne);
  // recuperam-se os 3 campos «casado», «filhos» e «salário» que formam $ligne
  list($marié, $enfants, $salaire) = explode(",", $ligne);
  // calcula-se o imposto
  $impôt = calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
  // regista-se o resultado no ficheiro de resultados
  fputs($résultats, "$marié:$enfants:$salaire:$impôt\n");
  // próximo contribuinte
}
// fecha-se os ficheiros
fclose($data);
fclose($résultats);

// fim
exit;

// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // elimina-se o marcador de fim de linha de $ligne, caso exista
  $L = strlen($ligne);  // comprimento da linha
  while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
    $ligne = substr($ligne, 0, $L - 1);
    $L--;
  }
  // fim
  return($ligne);
}

// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié: sim, não
  // $enfants: número de filhos
  // $salaire: salário anual
  // $limites, $coeffR, $coeffN: tabelas de dados que permitem o cálculo do imposto
  
  // número de quotas
  $marié = strtolower($marié);
  if ($marié == "oui")
    $nbParts = $enfants / 2 + 2;
  else
    $nbParts=$enfants / 2 + 1;
  // mais 1/2 quota se houver pelo menos 3 filhos
  if ($enfants >= 3)
    $nbParts+=0.5;
  // rendimento tributável
  $revenuImposable = 0.72 * $salaire;
  // quociente familiar
  $quotient = $revenuImposable / $nbParts;
  // é colocado no final da tabela de limites para interromper o ciclo seguinte
  array_push($limites, $quotient);
  // cálculo do imposto
  $i = 0;
  while ($quotient > $limites[$i])
    $i++;
  // uma vez que se colocou $quotient no final da tabela $limites, o ciclo anterior
  // não pode ultrapassar os limites da tabela $limites
  // agora podemos calcular o imposto
  return floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
}
?>

O ficheiro de dados data.txt (casado, filhos, salário):

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

Os ficheiros résultats.txt (estado civil, filhos, salário, impostos) dos resultados obtidos:

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

Comentários

  • linha 4: o nome do ficheiro de texto que contém os dados dos contribuintes (estado civil, filhos, salário)
  • linha 5: o nome do ficheiro de texto que contém os resultados (estado civil, filhos, salário, imposto) do cálculo do imposto
  • linhas 6-8: as três tabelas de dados que permitem o cálculo do imposto
  • linhas 11-15: abertura do ficheiro de dados dos contribuintes em modo de leitura
  • linhas 18-22: abertura do ficheiro de resultados para gravação
  • linha 25: ciclo de leitura das linhas (casado, filhos, salário) do ficheiro dos contribuintes
  • linha 27: o marcador de fim de linha é removido
  • linha 29: os componentes (casado, filhos, salário) da linha são recuperados
  • linha 31: o imposto é calculado
  • linha 33: o imposto é guardado no ficheiro de resultados
  • linhas 37-38: assim que o ficheiro dos contribuintes for totalmente processado, os ficheiros são fechados
  • linha 44: a função que remove o marcador de fim de linha de uma linha $ligne. O marcador de fim de linha é a cadeia «\r\n» nos sistemas Windows e «\n» nos sistemas Unix. O resultado é a cadeia de entrada sem o seu marcador de fim de linha.
  • linhas 47-48: substr($chaîne,$début,$taille) é a subcadeia de $chaîne que começa no carácter $début e tem, no máximo, $taille caracteres.
  • linha 63: strtolower($chaîne) transforma $chaîne em minúsculas
  • linha 76: array_push($tableau,$élément) adiciona $élément ao final da matriz $tableau. Note-se que a matriz $limites foi passada por valor para a função calculerImpot (linha 56: )). Esta adição de elemento é, portanto, efetuada na cópia do parâmetro efetivo, permanecendo este inalterado.
  • linha 84: a função floor($x) devolve o valor inteiro imediatamente inferior a $x.

4.3. Versão com ficheiros de texto (impots_02)

Esta nova versão difere da anterior apenas pelo facto de os dados ($limites, $coeffR, $coeffN) necessários para o cálculo do imposto se encontrarem agora num ficheiro de texto com o seguinte formato:

Ficheiro 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

A nova versão limita-se a ler os dados do ficheiro [impots.txt] para os inserir em três tabelas ($limites, $coeffR, $coeffN). Assim, voltamos ao caso anterior. Apresentamos apenas as alterações:


<?php

// definição das constantes
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
$IMPOTS = "impots.txt";

// os dados necessários para o cálculo do imposto foram colocados no ficheiro $IMPOTS
// à razão de uma linha por tabela, na forma
// val1:val2:val3,...
list($erreur, $limites, $coeffR, $coeffN) = getTables($IMPOTS);

// Houve algum erro?
if ($erreur) {
  print "$erreur\n";
  exit;
}//if
// leitura dos dados do utilizador
...

// fim
exit;

// --------------------------------------------------------------------------
function cutNewLinechar($ligne) {
  // elimina-se o marcador de fim de linha de $ligne, caso exista
...
}

// --------------------------------------------------------------------------
function calculImpots($marié, $enfants, $salaire, $limites, $coeffR, $coeffN) {
  // $marié: sim, não
  // $enfants: número de filhos
  // $salaire: salário anual
  // $limites, $coeffR, $coeffN: tabelas de dados que permitem o cálculo do imposto
  ...
}

// --------------------------------------------------------------------------
function getTables($IMPOTS) {
  // $IMPOTS: o nome do ficheiro que contém os dados das tabelas $limites, $coeffR, $coeffN
  // O ficheiro $IMPOTS existe?
  if (!file_exists($IMPOTS))
    return array("Le fichier $IMPOTS n'existe pas","","","");
  // leitura em bloco do ficheiro
  $tables = file($IMPOTS);
  if (!$tables)
    return array("Erreur lors de l'exploitation du fichier $IMPOTS","","","");
  // criação das 3 tabelas — parte-se do princípio de que as linhas estão sintaticamente corretas
  $limites = explode(":", cutNewLineChar($tables[0]));
  $coeffR = explode(":", cutNewLineChar($tables[1]));
  $coeffN = explode(":", cutNewLineChar($tables[2]));
  // fim
  return array("", $limites, $coeffR, $coeffN);
}
?>

Comentários

  • linha 11: a função getTables($IMPOTS) utiliza o ficheiro de texto $IMPOTS para extrair as três tabelas ($limites, $coeffR, $coeffN). O resultado obtido é ($erreur, $limites, $coeffR, $coeffN), em que $erreur é uma mensagem de erro, vazia caso não tenha ocorrido qualquer erro.
  • linha 40: a função getTables($IMPOTS).
  • linha 43: a função files_exists(nom_fichier) devolve o valor booleano true se o ficheiro nom_fichier existir; caso contrário, devolve o valor booleano false.
  • linha 46: a função file(nom_fichier) lê todo o ficheiro de texto nom_fichier. Devolve um tabuleiro em que cada elemento corresponde a uma linha do ficheiro de texto. Como, neste caso, o ficheiro impots.txt tem três linhas de texto, a função irá devolver um tabuleiro com três elementos.
  • linhas 50-52: utilização das três linhas recuperadas para criar os três tabuletos ($limites, $coeffR, $coeffN)

Os resultados obtidos são os mesmos que os da versão anterior.