Skip to content

4. Exercício prático – versões 1 e 2

4.1. O problema

Image

A tabela acima permite calcular o imposto no caso simplificado de um contribuinte que tenha apenas seu salário a declarar. Conforme indicado na nota (1), o imposto assim calculado é o imposto antes da aplicação de três mecanismos:

  • o teto do quociente familiar, que se aplica a rendas elevadas;
  • a dedução e a redução de impostos, que se aplicam a rendas baixas;

Assim, o cálculo do imposto compreende as seguintes etapas [http://impotsurlerevenu.org/comprendre-le-calcul-de-l-impot/1217-calcul-de-l-impot-2019.php]:

Image

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

4.1.1. Cálculo do imposto bruto

O imposto bruto pode ser calculado da seguinte forma:

Primeiro, calcula-se o número de cotas do contribuinte:

    • cada pai ou mãe contribui com 1 parte;
    • os dois primeiros filhos contribuem com 1/2 parte cada um;
    • os filhos seguintes contribuem com uma parte cada:

O número de partes é, portanto:

  • nbParts = 1 + nbEnfants * 0,5 + (nbEnfants - 2) * 0,5 se o empregado não for casado;
  • nbParts = 2 + nbEnfants * 0,5 + (nbEnfants - 2) * 0,5 se ele for casado;

onde nbEnfants é o número de filhos;

  • calcula-se a renda tributável R = 0,9 * S, onde S é o salário anual;
  • calcula-se o quociente familiar QF = R / nbParts;
  • calcula-se o imposto bruto I com base nos seguintes dados (2019):
9964
0
0
27.519
0,14
1.394,96
73.779
0,3
5.798
156.244
0,41
13.913,69
0
0,45
20163,45

Cada linha possui 3 campos: champ1, champ2, champ3. Para calcular o imposto I, procura-se a primeira linha em que QF ≤ campo1 e utilizam-se os valores dessa linha. Por exemplo, para um funcionário casado, com dois filhos e um salário anual S de 50.000 euros:

Renda tributável: R = 0,9 * S = 45.000

Número de cotas: nbParts = 2 + 2 * 0,5 = 3

Quociente familiar: QF = 45.000 / 3 = 15.000

A primeira linha em que QF <= campo1 é a seguinte:

    27519        0.14    1394.96

O imposto I é, então, igual a 0,14*R – 1.394,96*nbParts=[0,14*45000-1394,96*3]=2.115. O imposto é arredondado para o euro inferior.

Se a relação QF <= campo1 for verdadeira já na primeira linha, então o imposto é nulo.

Se QF for tal que a relação QF <= campo1 nunca for verificada, então são utilizados os coeficientes da última linha. Aqui:

    0            0.45        20163.45

o que resulta no imposto bruto I = 0,45 * R – 20.163,45 * nbParts.

4.1.2. Limite máximo do quociente familiar

Image

Para saber se o limite máximo do quociente familiar QF se aplica, refaz-se o cálculo do imposto bruto sem os filhos. Ainda para o empregado casado com dois filhos e um salário anual S de 50.000 euros:

Renda tributável: R = 0,9 * S = 45.000

Número de faixas: nbParts=2 (os filhos não são mais contabilizados)

Quociente familiar: QF = 45.000 / 2 = 22.500

A primeira linha em que QF <= campo1 é a seguinte:

    27519        0.14    1394.96

O imposto I é, portanto, igual a 0,14*R – 1.394,96*nbParts = [0,14*45000-1394,96*2] = 3.510.

Ganho máximo relacionado aos filhos: 1551 * 2 = 3102 euros

Imposto mínimo: 3.510 – 3.102 = 408 euros

O imposto bruto com 3 faixas, já calculado em 2.115 euros, é superior ao imposto mínimo de 408 euros; portanto, o teto familiar não se aplica neste caso.

De modo geral, o imposto bruto é maior que (imposto1, imposto2), onde:

  • [impôt1]: é o imposto bruto calculado com os filhos;
  • [impôt2]: é o imposto bruto calculado sem os filhos e deduzido do ganho máximo (aqui, 1.551 euros por meia-parte) relacionado aos filhos;

4.1.3. Cálculo da redução

Image

Ainda para o trabalhador casado com dois filhos e um salário anual S de 50.000 euros:

O imposto bruto (2.115) resultante da etapa anterior é inferior a 2.627 euros para um casal (1.595 euros para um solteiro): portanto, a redução se aplica. Ela é obtida pelo seguinte cálculo:

abatimento = limite (casal = 1.970 / solteiro = 1.196) – 0,75 * Imposto bruto

abatimento = 1.970 – 0,75 × 2.115 = 383,75, arredondado para 384 euros.

Novo imposto bruto = 2.115 – 384 = 1.731 euros

4.1.4. Cálculo da redução de impostos

Image

Abaixo de um determinado limite, é aplicada uma redução de 20% sobre o imposto bruto resultante dos cálculos anteriores. Em 2019, os limites são os seguintes:

  • solteiro: 21.037 euros;
  • casal: 42.074 euros; (o valor 37.968 utilizado no exemplo acima parece estar incorreto);

Esse limite é aumentado pelo valor: 3.797 * (número de meias-partes trazidas pelos filhos).

Ainda no caso do trabalhador casado com dois filhos e um salário anual S de 50.000 euros:

  • seu rendimento tributável (45.000 euros) é inferior ao limite (42.074 + 2 × 3.797) = 49.668 euros;
  • portanto, ele tem direito a uma redução de 20% do seu imposto: 1.731 * 0,2 = 346,2 euros, arredondado para 347 euros;
  • o imposto bruto do contribuinte passa a ser: 1.731 – 347 = 1.384 euros;

4.1.5. Cálculo do imposto líquido

Nosso cálculo termina aqui: o imposto líquido a pagar será de 1.384 euros. Na prática, o contribuinte pode se beneficiar de outras reduções, notadamente por doações a instituições de interesse público ou geral.

4.1.6. Caso dos rendimentos elevados

Nosso exemplo anterior corresponde à maioria dos casos de assalariados. No entanto, o cálculo do imposto é diferente no caso de rendas elevadas.

4.1.6.1. Limite máximo da redução de 10% sobre a renda anual

Na maioria dos casos, a renda tributável é obtida pela fórmula: R = 0,9 * S, em que S é o salário anual. Isso é chamado de redução de 10%. Essa redução tem um limite máximo. Em 2019:

  • ela não pode ser superior a 12.502 euros;
  • não pode ser inferior a 437 euros;

Consideremos o caso de um trabalhador solteiro, sem filhos, com um salário anual de 200.000 euros:

  • a redução de 10% é de 20.000 euros > 12.502 euros. Portanto, ela é reduzida para 12.502 euros;

4.1.6.2. Limite máximo do quociente familiar

Consideremos um caso em que se aplica o limite máximo familiar mencionado no parágrafo anterior. Tomemos o caso de um casal com três filhos e renda anual de 100.000 euros. Repassemos as etapas do cálculo:

  • A dedução de 10% corresponde a 10.000 euros < 12.502 euros. O rendimento tributável R é, portanto, 100.000 - 10.000 = 90.000 euros;
  • o casal tem nbParts = 2 + 0,5 × 2 + 1 = 4 partes;
  • seu quociente familiar é, portanto, QF = R / nbParts = 90.000 / 4 = 22.500 euros;
  • seu imposto bruto I1 com filhos é I1 = 0,14 × 90.000 – 1.394,96 × 4 = 7.020 euros;
  • seu imposto bruto I2 sem filhos:
    • QF = 90.000 / 2 = 45.000 euros;
    • I2 = 0,3 × 90.000 – 5.798 × 2 = 15.404 euros;
    • a regra do teto do quociente familiar estabelece que o ganho proporcionado pelos filhos não pode exceder (1.551 × 4 meias-partes) = 6.204 euros. No entanto, neste caso, ele é I2-I1 = 15.404 – 7.020 = 8.384 euros, portanto, superior a 6.204 euros;
    • o imposto bruto é, portanto, recalculado como I3 = I2-6204 = 15.404 – 6.204 = 9.200 euros;

Esse casal não terá dedução nem redução, e seu imposto final será de 9.200 euros.

4.1.7. Números oficiais

O cálculo do imposto é complexo. Ao longo do documento, os testes serão realizados com os exemplos a seguir. Os resultados são os do simulador da administração tributária [https://www3.impots.gouv.fr/simulateur/calcul_impot/2019/simplifie/index.htm]:

Contribuinte
Resultados oficiais
Resultados do algoritmo do documento
Casal com 2 filhos e renda anual de 55.555 euros
Imposto = 2.815 euros
Alíquota de imposto = 14%
Imposto = 2.814 euros
Alíquota de imposto = 14%
Casal com 2 filhos e renda anual de 50.000 euros
Imposto = 1.385 euros
Abatimento = 720 euros
Redução = 0 euros
Alíquota de imposto = 14%
Imposto = 1.384 euros
Abatimento = 384 euros
Redução = 347 euros
Alíquota de imposto = 14%
Casal com 3 filhos e renda anual de 50.000 euros
Imposto = 0 euro
Abatimento = 384 euros
Redução = 346 euros
Alíquota de imposto = 14%
Imposto = 0 euro
Desconto = 720 euros
Redução = 0 euros
Alíquota de imposto = 14%
Solteiro, com 2 filhos e renda anual de 100.000 euros
Imposto = 19.884 euros
Abatimento = 0 euros
Redução = 0 euro
Alíquota de imposto = 41%
Imposto = 19.884 euros
Sobretaxa = 4.480 euros
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 41%
Solteiro, com 3 filhos e renda anual de 100.000 euros
Imposto = 16.782 euros
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 41%
Imposto = 16.782 euros
Sobretaxa = 7.176 euros
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 41%
Casal com 3 filhos e renda anual de 100.000 euros
Imposto = 9.200 euros
Abatimento = 0 euro
Redução = 0 euros
Alíquota de imposto = 30%
Imposto = 9.200 euros
Sobretaxa = 2.180 euros
Desconto = 0 euro
Redução = 0 euro
Alíquota de imposto = 30%
Casal com 5 filhos e renda anual de 100.000 euros
Imposto = 4.230 euros
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 14%
Imposto = 4.230 euros
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 14%
Solteiro, sem filhos e com renda anual de 100.000 euros
Imposto = 22.986 euros
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 41%
Imposto = 22.986 euros
Sobretaxa = 0 euro
Desconto = 0 euro
Redução = 0 euro
Alíquota de imposto = 41%
Casal com 2 filhos e renda anual de 30.000 euros
Imposto = 0 euro
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 0%
Imposto = 0 euro
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 0%
Solteiro, sem filhos e com renda anual de 200.000 euros
Imposto = 64.211 euros
Abatimento = 0 euro
Redução = 0 euros
Alíquota de imposto = 45%
Imposto = 64.210 euros
Sobretaxa = 7.498 euros
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 45%
Casal com 3 filhos e renda anual de 200.000 euros
Imposto = 42.843 euros
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 41%
Imposto = 42.842 euros
Sobretaxa = 17.283 euros
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 41%

No exemplo acima, denomina-se “sobretaxa” o valor adicional que os rendimentos mais elevados pagam devido a dois fatores:

  • o teto de 10% para a dedução sobre a renda anual;
  • o limite máximo do quociente familiar;

Este indicador não pôde ser verificado, pois o simulador da administração tributária não o fornece.

Percebe-se que o algoritmo do documento calcula o imposto correto em todas as ocasiões, embora com uma margem de erro de 1 euro. Essa margem de erro decorre dos arredondamentos. Todos os valores monetários são arredondados, ora para o euro superior, ora para o euro inferior. Como eu não conhecia as regras oficiais, os valores monetários do algoritmo do documento foram arredondados:

  • para o euro superior no caso de descontos e reduções;
  • para o euro inferior, no caso das sobretaxas e do imposto final;

A seguir, serão realizados testes para verificar a validade dos resultados. Eles serão feitos com os exemplos da tabela anterior, com uma margem de erro aceitável de 1 euro.

4.2. A estrutura dos scripts

Image

4.3. Versão 1

4.3.1. O algoritmo

Apresentamos um primeiro programa em que:

  • os dados necessários para o cálculo do imposto estão codificados diretamente no código na forma de tabelas e constantes;
  • os dados dos contribuintes (casado, filhos, salário) estão em um primeiro arquivo de texto [taxpayersdata.txt];
  • os resultados do cálculo do imposto (casado, filhos, salário, imposto) são armazenados em um segundo arquivo de texto [resultats.txt];

O script [version-01/main.php] é o seguinte:


<?php

// tipos estritos para parâmetros de funções
declare(strict_types=1);

// constantes globais
define("PLAFOND_QF_DEMI_PART", 1551);
define("PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION", 21037);
define("PLAFOND_REVENUS_COUPLE_POUR_REDUCTION", 42074);
define("VALEUR_REDUC_DEMI_PART", 3797);
define("PLAFOND_DECOTE_CELIBATAIRE", 1196);
define("PLAFOND_DECOTE_COUPLE", 1970);
define("PLAFOND_IMPOT_COUPLE_POUR_DECOTE", 2627);
define("PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE", 1595);
define("ABATTEMENT_DIXPOURCENT_MAX", 12502);
define("ABATTEMENT_DIXPOURCENT_MIN", 437);

// definição de constantes locais
$DATA = "taxpayersdata.txt";
$RESULTATS = "resultats.txt";
$limites = array(9964, 27519, 73779, 156244, 0);
$coeffR = array(0, 0.14, 0.3, 0.41, 0.45);
$coeffN = array(0, 1394.96, 5798, 13913.69, 20163.45);

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

// abertura do arquivo 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 arquivo de dados
while ($ligne = fgets($data, 100)) {
  // remove-se o eventual caractere de fim de linha
  $ligne = cutNewLineChar($ligne);
  // recuperam-se os três campos “casado:filhos:salário” que formam $ligne
  list($marié, $enfants, $salaire) = explode(",", $ligne);
  // calcula-se o imposto
  $result = calculImpot($marié, (int) $enfants, (float) $salaire, $limites, $coeffR, $coeffN);
  // insere-se o resultado no arquivo de resultados
  $result = ["marié" => $marié, "enfants" => $enfants, "salaire" => $salaire] + $result;
  fputs($résultats, \json_encode($result, JSON_UNESCAPED_UNICODE) . "\n");
  // próximo dado
}
// fecha-se os arquivos
fclose($data);
fclose($résultats);

// fim
exit;

// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne): string {
  // remove-se o marcador de fim de linha de $ligne, se houver
  $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);
}

// cálculo do imposto
// --------------------------------------------------------------------------
function calculImpot(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {

  // resultado
  return ["impôt" => floor($impot), "surcôte" => $surcôte, "décôte" => $décôte, "réduction" => $réduction, "taux" => $taux];
}

// --------------------------------------------------------------------------
function calculImpot2(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {

  // resultado
  return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}

// revenuImposable=salárioAnual-abatimento
// a dedução tem um valor mínimo e um valor máximo
function getRevenuImposable(float $salaire): float {

  // resultado
  return floor($revenuImposable);
}

// calcula uma eventual redução
function getDecote(string $marié, float $salaire, float $impots): float {

  // resultado
  return ceil($décôte);
}

// calcula uma eventual redução
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {
  /
  // resultado
  return ceil($réduction);
}

O arquivo de dados taxpayersdata.txt (casado, filhos, salário):

oui,2,55555
oui,2,50000
oui,3,50000
non,2,100000
non,3,100000
oui,3,100000
oui,5,100000
non,0,100000
oui,2,30000
non,0,200000
oui,3,200000

Os arquivos résultats.txt (estado civil, filhos, salário, imposto, acréscimo, dedução, redução, alíquota de imposto) dos resultados obtidos:

{"marié":"oui","enfants":"2","salaire":"55555","impôt":2814,"surcôte":0,"décôte":0,"réduction":0,"taux":0.14}
{"marié":"oui","enfants":"2","salaire":"50000","impôt":1384,"surcôte":0,"décôte":384,"réduction":347,"taux":0.14}
{"marié":"oui","enfants":"3","salaire":"50000","impôt":0,"surcôte":0,"décôte":720,"réduction":0,"taux":0.14}
{"marié":"non","enfants":"2","salaire":"100000","impôt":19884,"surcôte":4480,"décôte":0,"réduction":0,"taux":0.41}
{"marié":"non","enfants":"3","salaire":"100000","impôt":16782,"surcôte":7176,"décôte":0,"réduction":0,"taux":0.41}
{"marié":"oui","enfants":"3","salaire":"100000","impôt":9200,"surcôte":2180,"décôte":0,"réduction":0,"taux":0.3}
{"marié":"oui","enfants":"5","salaire":"100000","impôt":4230,"surcôte":0,"décôte":0,"réduction":0,"taux":0.14}
{"marié":"non","enfants":"0","salaire":"100000","impôt":22986,"surcôte":0,"décôte":0,"réduction":0,"taux":0.41}
{"marié":"oui","enfants":"2","salaire":"30000","impôt":0,"surcôte":0,"décôte":0,"réduction":0,"taux":0}
{"marié":"non","enfants":"0","salaire":"200000","impôt":64210,"surcôte":7498,"décôte":0,"réduction":0,"taux":0.45}
{"marié":"oui","enfants":"3","salaire":"200000","impôt":42842,"surcôte":17283,"décôte":0,"réduction":0,"taux":0.41}

Comentários

  • linha 4: exige-se o cumprimento estrito do tipo dos parâmetros das funções;
  • linhas 7-16: definição de todas as constantes necessárias para o cálculo do imposto;
  • linha 19: o nome do arquivo de texto contendo os dados dos contribuintes (casado, filhos, salário);
  • linha 20: o nome do arquivo de texto que contém os resultados (estado civil, filhos, salário, imposto) do cálculo do imposto;
  • linhas 21-23: as três tabelas de dados que definem as diferentes faixas de tributação do cálculo do imposto;
  • linhas 26-30: abertura para leitura [r] do arquivo de dados dos contribuintes. A função [fopen] retorna o valor booleano FALSE caso a abertura não tenha sido possível;
  • linhas 33-37: abertura para gravação [w] do arquivo de resultados;
  • linhas 40-51: loop de leitura das linhas (cônjuge, filhos, salário) do arquivo de dados dos contribuintes;
  • linha 40: a função [fgets] lê 100 caracteres e para na primeira marca de fim de linha encontrada. Aqui, todas as linhas têm menos de 100 caracteres. Se um marcador de fim de linha for encontrado, ele é incluído na string retornada. Quando o fim do arquivo é encontrado, a função [fgets] retorna o valor FALSE;
  • linha 42: o caractere de fim de linha é removido;
  • linha 44: os componentes (cônjuge, filhos, salário) da linha são recuperados;
  • linha 46: o imposto é calculado. O resultado é retornado na forma de uma tabela associativa (linha 76);
  • linha 48: ao array recuperado anteriormente, são adicionadas as chaves [marié, enfants, salaire];
  • linha 49: o resultado é armazenado no arquivo de resultados na forma de uma cadeia de caracteres jSON;
  • linhas 53-54: uma vez que o arquivo de dados dos contribuintes foi totalmente processado, os arquivos são fechados;
  • linha 60: a função que remove o caractere de fim de linha de uma linha $ligne. O caractere de fim de linha é a sequência “\r\n” nos sistemas Windows e “\n” nos sistemas Unix. O resultado é a sequência de entrada sem o caractere de fim de linha.
  • linhas 63-64: substr($chaîne,$début,$taille) é a subcadeia de $chaîne que começa no caractere $début e tem, no máximo, $taille caracteres;

A função [calculImpot] é a seguinte:


// constantes globais
define("PLAFOND_QF_DEMI_PART", 1551);

// cálculo do imposto
// --------------------------------------------------------------------------
function calculImpot(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
  // $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
  //
  // cálculo do imposto com filhos
  $result1 = calculImpot2($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
  $impot1 = $result1["impôt"];
  // cálculo do imposto sem filhos
  if ($enfants != 0) {
    $result2 = calculImpot2($marié, 0, $salaire, $limites, $coeffR, $coeffN);
    $impot2 = $result2["impôt"];
    // aplicação do limite máximo do quociente familiar
    if ($enfants < 3) {
      // $PLAFOND_QF_DEMI_PART euros para os dois primeiros filhos
      $impot2 = $impot2 - $enfants * PLAFOND_QF_DEMI_PART;
    } else {
      // $PLAFOND_QF_DEMI_PART euros para os dois primeiros filhos, o dobro para os seguintes
      $impot2 = $impot2 - 2 * PLAFOND_QF_DEMI_PART - ($enfants - 2) * 2 * PLAFOND_QF_DEMI_PART;
    }
  } else {
    $impot2 = $impot1;
    $result2 = $result1;
  }
  // considera-se o imposto mais alto, com a alíquota e a sobretaxa correspondentes
  if ($impot1 > $impot2) {
    $impot = $impot1;
    $taux = $result1["taux"];
    $surcôte = $result1["surcôte"];
  } else {
    $surcôte = $impot2 - $impot1 + $result2["surcôte"];
    $impot = $impot2;
    $taux = $result2["taux"];
  }
  // cálculo de uma eventual redução
  $décôte = getDecote($marié, $salaire, $impot);
  $impot -= $décôte;
  // cálculo de uma eventual redução de impostos
  $réduction = getRéduction($marié, $salaire, $enfants, $impot);
  $impot -= $réduction;
  // resultado
  return ["impôt" => floor($impot), "surcôte" => $surcôte, "décôte" => $décôte, "réduction" => $réduction, "taux" => $taux];
}

// --------------------------------------------------------------------------
function calculImpot2(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {

  // resultado
  return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}

// revenuImposable=salárioAnual-abatimento
// a dedução de 10% tem um valor mínimo e um valor máximo
function getRevenuImposable(float $salaire): float {

}

// calcula uma eventual redução
function getDecote(string $marié, float $salaire, float $impots): float {

  // resultado
  return ceil($décôte);
}

// calcula uma eventual redução
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {

  // resultado
  return ceil($réduction);
}

Comentários

  • linha 10: o imposto bruto é calculado incluindo os filhos. O resultado obtido é da forma ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]] com:
    • [‘impôt’]: o imposto bruto;
    • [‘surcôte’]: o valor da sobretaxa, se houver. Ela se aplica quando a dedução de 10% ultrapassa o limite de 12.502 euros;
    • [‘taux’]: a alíquota de imposto do contribuinte;
  • linha 11: o imposto bruto a pagar [impot1];
  • linhas 13-14: se o contribuinte tiver pelo menos um filho, o cálculo do imposto é refeito com os mesmos dados, mas considerando 0 filho. Esse segundo cálculo é necessário para verificar se a redução decorrente dos filhos (nbParts*coeffN) é superior a um determinado limite;
  • linha 15: o imposto bruto [impot2] a ser pago;
  • linhas 16-23: para o imposto bruto [impot2], agora levam-se em conta os filhos: cada 1/2 parte decorrente dos filhos permite uma redução de [PLAFOND_QF_DEMI_PART] euros;
  • linhas 25-26: caso em que o contribuinte não tenha filhos. Nesse caso, o cálculo de [impot2] é desnecessário. Ele é igual a [impot1];
  • linhas 29-37: foram calculados dois impostos brutos [impot1, impot2]. A administração fiscal considera o maior dos dois. Obtém-se um imposto bruto [impot];
  • linhas 39-40: o valor bruto [impot] pode sofrer uma redução;
  • linhas 42-43: o valor bruto [impot] pode sofrer uma redução;
  • linha 45: [impot] é agora o imposto líquido a pagar. Retornamos os resultados;

A função [calculImpot2] é a seguinte:


// --------------------------------------------------------------------------
function calculImpot2(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
  // $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 cotas
  $marié = strtolower($marié);
  if ($marié === "oui") {
    $nbParts = $enfants / 2 + 2;
  } else {
    $nbParts = $enfants / 2 + 1;
  }
  // 1 parcela por filho a partir do terceiro
  if ($enfants >= 3) {
    // meia parcela adicional para cada filho a partir do terceiro
    $nbParts += 0.5 * ($enfants - 2);
  }
  // renda tributável
  $revenuImposable = getRevenuImposable($salaire);
  // sobretaxa
  $surcôte = floor($revenuImposable - 0.9 * $salaire);
  // para problemas de arredondamento
  if ($surcôte < 0) {
    $surcôte = 0;
  }
  // quociente familiar
  $quotient = $revenuImposable / $nbParts;
  // é inserido no final da tabela de limites para interromper o ciclo a seguir
  $limites[count($limites) - 1] = $quotient;
  // cálculo do imposto
  $i = 0;
  while ($quotient > $limites[$i]) {
    $i++;
  }
  // como colocamos $quotient no final da tabela $limites, o loop anterior
  // não pode ultrapassar os limites da tabela $limites
  //; agora podemos calcular o imposto
  $impôt = floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
  // resultado
  return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}

// revenuImposable = salárioAnual - dedução
// a dedução tem um valor mínimo e um valor máximo
function getRevenuImposable(float $salaire): float {
  
  // resultado
  return floor($revenuImposable);
}

Comentários

  • aplica-se aqui o cálculo do imposto segundo a tabela progressiva;
  • linha 9: strtolower($chaîne) converte $chaîne em letras minúsculas;
  • linhas 10-19: cálculo do número de cotas do contribuinte;
  • linha 21: calcula-se a renda tributável por meio de uma função. De fato, vimos que nem sempre é 0,9*revenusAnnuels. A dedução de 10% é, de fato, limitada a 12.502 euros;
  • linha 23: cálculo da eventual sobretaxa caso o rendimento tributável seja superior a 0,9*revenusAnnuels;
  • linhas 25-27: corrige o fato de que, devido a erros de arredondamento, às vezes se obtém [$surcôte=-1];
  • linha 29: o quociente familiar;
  • linhas 30-36: esse quociente permite determinar a faixa de tributação do contribuinte;
  • linha 40: uma vez determinada a faixa de tributação do contribuinte, seu imposto bruto pode ser calculado. A função floor($x) retorna o valor inteiro imediatamente inferior a [$x];
  • linha 42: as informações calculadas são exibidas;

A função [getRevenuImposable] é a seguinte:


// constantes globais
define("ABATTEMENT_DIXPOURCENT_MAX", 12502);
define("ABATTEMENT_DIXPOURCENT_MIN", 437);

// revenuImposable=salárioAnual-abatimento
// a dedução tem um valor mínimo e um valor máximo
function getRevenuImposable(float $salaire): float {
  // abatimento de 10% do salário
  $abattement = 0.1 * $salaire;
  // essa dedução não pode exceder ABATTEMENT_DIXPOURCENT_MAX
  if ($abattement > ABATTEMENT_DIXPOURCENT_MAX) {
    $abattement = ABATTEMENT_DIXPOURCENT_MAX;
  }
  // a dedução não pode ser inferior a ABATTEMENT_DIXPOURCENT_MIN
  if ($abattement < ABATTEMENT_DIXPOURCENT_MIN) {
    $abattement = ABATTEMENT_DIXPOURCENT_MIN;
  }
  // renda tributável
  $revenuImposable = $salaire - $abattement;
  // resultado
  return floor($revenuImposable);
}

Comentários

  • linha 5: a dedução normal é de 10% do salário anual;
  • linhas 7-9: a dedução não pode exceder a dedução máxima [ABATTEMENT_DIXPOURCENT_MAX];
  • linhas 10 a 13: a dedução não pode ser inferior à dedução mínima [ABATTEMENT_DIXPOURCENT_MIN];
  • linha 15: cálculo da renda tributável;

A função [getDecote] é a seguinte:


// constantes globais
define("PLAFOND_DECOTE_CELIBATAIRE", 1196);
define("PLAFOND_DECOTE_COUPLE", 1970);
define("PLAFOND_IMPOT_COUPLE_POUR_DECOTE", 2627);
define("PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE", 1595);

// calcula um eventual desconto
function getDecote(string $marié, float $salaire, float $impots): float {
  // inicialmente, um desconto nulo
  $décôte = 0;
  // valor máximo do imposto para que haja redução
  $plafondImpôtPourDécôte = $marié === "oui" ? PLAFOND_IMPOT_COUPLE_POUR_DECOTE : PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE;
  if ($impots < $plafondImpôtPourDécôte) {
    // valor máximo do desconto
    $plafondDécôte = $marié === "oui" ? PLAFOND_DECOTE_COUPLE : PLAFOND_DECOTE_CELIBATAIRE;
    // abatimento teórico
    $décôte = $plafondDécôte - 0.75 * $impots;
    // a redução não pode exceder o valor do imposto
    if ($décôte > $impots) {
      $décôte = $impots;
    }
    // não há abatimento <0
    if ($décôte < 0) {
      $décôte = 0;
    }
  }
  // resultado
  return ceil($décôte);
}

Observações

  • linha 6: valor máximo do imposto bruto para ter direito a uma redução. Esse valor é diferente para solteiros e casais;
  • linha 7: se o contribuinte tem direito à redução;
  • linha 11: a fórmula da redução. [plafondDécôte] é o valor máximo da redução. Esse valor máximo é calculado na linha 9. Mais uma vez, ele depende da situação do contribuinte, casado ou solteiro;
  • linhas 13-15: a dedução não pode ser superior ao imposto bruto a pagar. Esse é o caso, por exemplo, se [impots] for igual a 0 na linha 11;
  • linhas 17-19: para evitar um arredondamento para -1;

A função [getRéduction] é a seguinte:


// constantes globais
define("PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION", 21037);
define("PLAFOND_REVENUS_COUPLE_POUR_REDUCTION", 42074);
define("VALEUR_REDUC_DEMI_PART", 3797);

// calcula uma eventual redução
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {
  // o teto de renda para ter direito à redução de 20%
  $plafondRevenuPourRéduction = $marié === "oui" ? PLAFOND_REVENUS_COUPLE_POUR_REDUCTION : PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION;
  $plafondRevenuPourRéduction += $enfants * VALEUR_REDUC_DEMI_PART;
  if ($enfants > 2) {
    $plafondRevenuPourRéduction += ($enfants - 2) * VALEUR_REDUC_DEMI_PART;
  }
  // renda tributável
  $revenuImposable = getRevenuImposable($salaire);
  // redução
  $réduction = 0;
  if ($revenuImposable < $plafondRevenuPourRéduction) {
    // redução de 20%
    $réduction = 0.2 * $impots;
  }
  // resultado
  return ceil($réduction);
}

Observações

  • linhas 4-10: para ter direito a uma redução de imposto, é necessário que a renda tributável (linha 10) seja inferior a um limite máximo calculado nas linhas 4-8;
  • linhas 13-16: se atender às condições, o contribuinte tem direito a uma redução de imposto de 20% (linha 15);

4.3.2. Resultados

O arquivo de dados taxpayersdata.txt (casado, filhos, salário):

oui,2,55555
oui,2,50000
oui,3,50000
non,2,100000
non,3,100000
oui,3,100000
oui,5,100000
non,0,100000
oui,2,30000
non,0,200000
oui,3,200000

Os arquivos résultats.txt (casado, filhos, salário, imposto, acréscimo, dedução, redução, alíquota de imposto) dos resultados obtidos:

{"marié":"oui","enfants":"2","salaire":"55555","impôt":2814,"surcôte":0,"décôte":0,"réduction":0,"taux":0.14}
{"marié":"oui","enfants":"2","salaire":"50000","impôt":1384,"surcôte":0,"décôte":384,"réduction":347,"taux":0.14}
{"marié":"oui","enfants":"3","salaire":"50000","impôt":0,"surcôte":0,"décôte":720,"réduction":0,"taux":0.14}
{"marié":"non","enfants":"2","salaire":"100000","impôt":19884,"surcôte":4480,"décôte":0,"réduction":0,"taux":0.41}
{"marié":"non","enfants":"3","salaire":"100000","impôt":16782,"surcôte":7176,"décôte":0,"réduction":0,"taux":0.41}
{"marié":"oui","enfants":"3","salaire":"100000","impôt":9200,"surcôte":2180,"décôte":0,"réduction":0,"taux":0.3}
{"marié":"oui","enfants":"5","salaire":"100000","impôt":4230,"surcôte":0,"décôte":0,"réduction":0,"taux":0.14}
{"marié":"non","enfants":"0","salaire":"100000","impôt":22986,"surcôte":0,"décôte":0,"réduction":0,"taux":0.41}
{"marié":"oui","enfants":"2","salaire":"30000","impôt":0,"surcôte":0,"décôte":0,"réduction":0,"taux":0}
{"marié":"non","enfants":"0","salaire":"200000","impôt":64210,"surcôte":7498,"décôte":0,"réduction":0,"taux":0.45}
{"marié":"oui","enfants":"3","salaire":"200000","impôt":42842,"surcôte":17283,"décôte":0,"réduction":0,"taux":0.41}

Os resultados obtidos estão em conformidade com os obtidos com o simulador da administração tributária.

4.3.3. Conclusão

O algoritmo de cálculo do imposto, mesmo em casos considerados simples, é complexo. Não voltaremos a abordá-lo. Ao longo das versões, sua essência permanecerá a mesma, apesar de algumas mudanças na apresentação. Portanto, comentaremos apenas estas últimas.

4.4. Versão 2

4.4.1. As modificações

Na versão anterior, os dados necessários para o cálculo do imposto estavam codificados de forma estática na forma de constantes e tabelas. Esse método deve ser evitado. Na nova versão, esses dados foram externalizados em um arquivo jSON:

Image

O conteúdo do arquivo [taxadmindata.json] é o seguinte:


{
    "limites": [9964, 27519, 73779, 156244, 0],
    "coeffR": [0, 0.14, 0.3, 0.41, 0.45],
    "coeffN": [0, 1394.96, 5798, 13913.69, 20163.45],
    "PLAFOND_QF_DEMI_PART": 1551,
    "PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION": 21037,
    "PLAFOND_REVENUS_COUPLE_POUR_REDUCTION": 42074,
    "VALEUR_REDUC_DEMI_PART": 3797,
    "PLAFOND_DECOTE_CELIBATAIRE": 1196,
    "PLAFOND_DECOTE_COUPLE": 1970,
    "PLAFOND_IMPOT_COUPLE_POUR_DECOTE": 2627,
    "PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE": 1595,
    "ABATTEMENT_DIXPOURCENT_MAX": 12502,
    "ABATTEMENT_DIXPOURCENT_MIN": 437
}

A nova versão [version-02/main.php] é a seguinte:


<?php

// respeito estrito aos tipos declarados dos parâmetros das funções
declare (strict_types=1);

// definição das constantes
$TAXPAYERSDATA = "taxpayersdata.txt";
$RESULTATS = "resultats.txt";
$TAXADMINDATA = "taxadmindata.json";

// recuperamos o conteúdo do arquivo de dados fiscais
$fileContents = \file_get_contents($TAXADMINDATA);
$erreur = FALSE;
// erro?
if (!$fileContents) {
  // registra-se o erro
  $erreur = TRUE;
  $message = "Le fichier des données [$TAXADMINDATA] n'existe pas";
}

if (!$erreur) {
  // recuperação do código jSON do arquivo de configuração em uma tabela associativa
  $taxAdminData = \json_decode($fileContents, true);
  // erro?
  if (!$taxAdminData) {
    // registra-se o erro
    $erreur = TRUE;
    $message = "Le fichier de données jSON [$TAXADMINDATA] n'a pu être exploité correctement";
  }
}

// erro?
if ($erreur) {
  print "$message\n";
  exit;
}

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

// abertura do arquivo de dados dos contribuintes
$taxpayersdata = fopen($TAXPAYERSDATA, "r");
if (!$taxpayersdata) {
  print "Impossible d'ouvrir le fichier des contribuables [$TAXPAYERSDATA]\n";
  // saída
  exit;
}

// processando a linha atual do arquivo de dados
while ($ligne = fgets($taxpayersdata, 100)) {
  // remove-se a eventual marca de fim de linha
  $ligne = cutNewLineChar($ligne);
  // recupera-se os 3 campos casado:filhos:salário que formam $ligne
  list($marié, $enfants, $salaire) = explode(",", $ligne);
  // calcula-se o imposto
  $result = calculImpot($taxAdminData, $marié, (int) $enfants, (int) $salaire);
  // insere-se o resultado no arquivo de resultados
  $result = ["marié" => $marié, "enfants" => $enfants, "salaire" => $salaire] + $result;
  fputs($résultats, \json_encode($result, JSON_UNESCAPED_UNICODE) . "\n");
  // próximo dado
}
// fecha-se os arquivos
fclose($taxpayersdata);
fclose($résultats);

// fim
exit;

// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne) {

  // fim
  return($ligne);
}

// cálculo do imposto
// --------------------------------------------------------------------------
function calculImpot(array $taxAdminData, string $marié, int $enfants, float $salaire) {
  // $marié: sim, não
  // $enfants: número de filhos
  // $salaire: salário anual
  // $taxAdminData: dados da administração fiscal
  //
  // cálculo do imposto com filhos
  $result1 = calculImpot2($taxAdminData, $marié, $enfants, $salaire);
  $impot1 = $result1["impôt"];
  // cálculo do imposto sem filhos
  if ($enfants != 0) {
    $result2 = calculImpot2($taxAdminData, $marié, 0, $salaire);
    $impot2 = $result2["impôt"];
    // aplicação do limite máximo do quociente familiar
    if ($enfants < 3) {
      // $PLAFOND_QF_DEMI_PART euros para os dois primeiros filhos
      $impot2 = $impot2 - $enfants * $taxAdminData["PLAFOND_QF_DEMI_PART"];
    } else {
      // $PLAFOND_QF_DEMI_PART euros para os dois primeiros filhos, o dobro para os seguintes
      $impot2 = $impot2 - 2 * $taxAdminData["PLAFOND_QF_DEMI_PART"] - ($enfants - 2) * 2 * $taxAdminData["PLAFOND_QF_DEMI_PART"];
    }
  } else {
    $impot2 = $impot1;
    $result2 = $result1;
  }
  // considera-se o imposto mais alto, com a alíquota e a sobretaxa correspondentes
  if ($impot1 > $impot2) {
    $impot = $impot1;
    $taux = $result1["taux"];
    $surcôte = $result1["surcôte"];
  } else {
    $surcôte = $impot2 - $impot1 + $result2["surcôte"];
    $impot = $impot2;
    $taux = $result2["taux"];
  }
  // cálculo de uma eventual redução
  $décôte = getDecote($taxAdminData, $marié, $salaire, $impot);
  $impot -= $décôte;
  // cálculo de uma eventual redução de impostos
  $réduction = getRéduction($taxAdminData, $marié, $salaire, $enfants, $impot);
  $impot -= $réduction;
  // resultado
  return ["impôt" => floor($impot), "surcôte" => $surcôte, "décôte" => $décôte, "réduction" => $réduction, "taux" => $taux];
}

// --------------------------------------------------------------------------
function calculImpot2(array $taxAdminData, string $marié, int $enfants, float $salaire) {
  // $marié: sim, não

  // resultado
  return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}

// revenuImposable=salárioAnual-abatimento
// a dedução tem um valor mínimo e um valor máximo
function getRevenuImposable(array $taxAdminData, float $salaire): float {

  // resultado
  return floor($revenuImposable);
}

// calcula uma eventual redução
function getDecote(array $taxAdminData, string $marié, float $salaire, float $impots): float {

  // resultado
  return ceil($décôte);
}

// calcula uma eventual redução
function getRéduction(array $taxAdminData, string $marié, float $salaire, int $enfants, float $impots): float {

  // resultado
  return ceil($réduction);
}

Comentários

  • linhas 11-19: tenta-se ler o conteúdo do arquivo jSON, denominado [TAXADMINDATA];
  • linhas 21-30: se foi possível ler o arquivo jSON, seu conteúdo é decodificado na tabela associativa [$taxAdminData];
  • linhas 32-36: se ocorrer um erro em uma das duas operações anteriores, é exibida uma mensagem de erro no console e o programa é encerrado;
  • a diferença em relação à versão 01 é que, aqui, os dados (tabelas e constantes) da administração fiscal estão na tabela associativa [$taxAdminData], enquanto na versão 01 eles estavam em tabelas e constantes globais. É o caráter global dessas constantes que faz a diferença entre as duas versões:
    • na versão 01, as constantes eram reconhecidas em todas as funções de [main.php];
    • para obter o mesmo resultado na versão 02, é necessário passar a tabela associativa [$taxAdminData] como parâmetro para todas as funções (linhas 83, 129, 138, 145, 152);
  • cada função da versão 02 deve utilizar o conteúdo da matriz [$taxAdminData];
  • linhas 83-126: na função [calculerImpot], onde antes se utilizavam constantes globais ou as tabelas [limites, coeffR, coeffN], agora utiliza-se o conteúdo da tabela [$taxAdminData] recebida como parâmetro (linhas 99, 102);
  • todas as outras funções foram reescritas da mesma forma;

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

4.4.2. Conclusão

A versão 02 é bem mais flexível do que a versão 01. Em 2020, o algoritmo de cálculo do imposto provavelmente será o mesmo de 2019. Apenas as faixas de tributação e as constantes de cálculo terão mudado. Bastará, então, atualizar o arquivo [taxadmindata.json]. Com a versão 01, é preciso acessar o código para modificar as faixas de tributação e as constantes de cálculo. No entanto, é provável que as pessoas que precisam alterar os valores das faixas de tributação e das constantes de cálculo não tenham acesso ao código do algoritmo.