Skip to content

4. Esercizio pratico – Versioni 1 e 2

4.1. Il problema

Image

La tabella sopra riportata consente di calcolare l'imposta nel caso semplificato di un contribuente che deve dichiarare solo il proprio stipendio. Come indicato nella nota (1), l'imposta calcolata in questo modo è l'imposta al lordo di tre meccanismi:

  • il limite del quoziente familiare, che si applica ai redditi elevati;
  • il credito d'imposta e la riduzione d'imposta che si applicano ai redditi bassi;

Pertanto, il calcolo dell'imposta prevede le seguenti fasi [http://impotsurlerevenu.org/comprendre-le-calcul-de-l-impot/1217-calcul-de-l-impot-2019.php]:

Image

Proponiamo di scrivere un programma per calcolare l'imposta di un contribuente nel caso semplificato di un contribuente che ha solo lo stipendio da dichiarare:

4.1.1. Calcolo dell'imposta lorda

L'imposta lorda può essere calcolata come segue:

Per prima cosa, calcoliamo il numero di quote del contribuente:

    • ogni genitore contribuisce con 1 quota;
    • I primi due figli apportano ciascuno 1/2 quota;
    • i figli rimanenti apportano ciascuno una quota:

Il numero di quote è quindi:

  • nbParts=1+nbChildren*0,5+(nbChildren-2)*0,5 se il dipendente è celibe;
  • nbParts = 2 + nbChildren * 0,5 + (nbChildren - 2) * 0,5 se è sposato;

dove nbFigli è il numero di figli;

  • calcoliamo il reddito imponibile R = 0,9 * S, dove S è lo stipendio annuale;
  • il quoziente familiare QF si calcola come QF = R / nbParts;
  • calcoliamo l'imposta lorda I sulla base dei seguenti dati (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
20.163,45

Ogni riga ha 3 campi: campo1, campo2, campo3. Per calcolare l'imposta I, cerchiamo la prima riga in cui QF <= campo1 e prendiamo i valori da quella riga. Ad esempio, per un dipendente sposato con due figli e uno stipendio annuo S di 50.000 euro:

Reddito imponibile: R=0,9*S=45.000

Numero di quote: nbParts=2+2*0,5=3

Quoziente familiare: QF=45.000/3=15.000

La prima riga in cui QF <= campo1 è la seguente:

    27519        0.14    1394.96

L'imposta I è quindi pari a 0,14*R – 1394,96*numeroDiAzioni=[0,14*45000-1394,96*3]=2115. L'imposta viene arrotondata per difetto all'euro più vicino.

Se nella prima riga si verifica la condizione QF <= campo1, l'imposta è pari a zero.

Se QF è tale che la condizione QF <= campo1 non è mai soddisfatta, vengono utilizzati i coefficienti dell'ultima riga. Qui:

    0            0.45        20163.45

il che dà l'imposta lorda I = 0,45*R – 20163,45*nbParts.

4.1.2. Limite del quoziente familiare

Image

Per determinare se si applica il limite del quoziente familiare (QF), ricalcoliamo l'imposta lorda senza i figli. Ancora una volta, per il dipendente sposato con due figli e uno stipendio annuo S di 50.000 euro:

Reddito imponibile: R = 0,9 * S = 45.000

Numero di quote: nbParts=2 (i figli non vengono più conteggiati)

Quoziente familiare: QF = 45.000 / 2 = 22.500

La prima riga in cui QF <= campo1 è la seguente:

    27519        0.14    1394.96

L'imposta I è quindi pari a 0,14*R – 1394,96*numero di azioni = [0,14*45.000 – 1394,96*2] = 3.510.

Indennità massima per figli a carico: 1551 * 2 = 3102 euro

Imposta minima: 3.510 – 3.102 = 408 euro

L'imposta lorda con 3 scaglioni fiscali, già calcolata a 2.115 euro, è superiore all'imposta minima di 408 euro, quindi in questo caso non si applica il limite familiare.

In generale, l'imposta lorda è maggiore di (imposta1, imposta2) dove:

  • [imposta1]: è l'imposta lorda calcolata includendo i figli;
  • [imposta2]: è l'imposta lorda calcolata senza figli e ridotta del credito massimo (in questo caso 1.551 euro per metà quota) relativo ai figli;

4.1.3. Calcolo della riduzione fiscale

Image

Sempre per il dipendente coniugato con due figli e uno stipendio annuo S di 50.000 euro:

L'imposta lorda (2.115) del passaggio precedente è inferiore a 2.627 euro per una coppia (1.595 euro per una persona sola): si applica quindi la riduzione d'imposta. Essa si calcola come segue:

sconto = soglia (coppia = 1.970 / single = 1.196) - 0,75 * imposta lorda

sconto = 1.970 – 0,75 * 2.115 = 383,75, arrotondato a 384 euro.

Nuova imposta lorda = 2.115 – 384 = 1.731 euro

4.1.4. Calcolo della riduzione fiscale

Image

Al di sotto di una certa soglia, viene applicata una riduzione del 20% all'imposta lorda risultante dai calcoli precedenti. Nel 2019, le soglie sono le seguenti:

  • Single: 21.037 euro;
  • coppia: 42.074 euro; (la cifra 37.968 utilizzata nell'esempio sopra riportato sembra essere errata);

Questa soglia viene aumentata del valore: 3.797 * (numero di quote pari alla metà versate dai figli).

Ancora una volta, per il dipendente sposato con due figli e uno stipendio annuo S di 50.000 euro:

  • il suo reddito imponibile (45.000 euro) è inferiore alla soglia (42.074 + 2 × 3.797) = 49.668 euro;
  • ha quindi diritto a una riduzione del 20% della sua imposta: 1.731 * 0,2 = 346,2 euro, arrotondati a 347 euro;
  • l'imposta lorda del contribuente diventa: 1.731 – 347 = 1.384 euro;

4.1.5. Calcolo dell'imposta netta

Il nostro calcolo termina qui: l'imposta netta dovuta sarà di 1.384 euro. In realtà, il contribuente potrebbe avere diritto ad altre detrazioni, in particolare per le donazioni a organizzazioni pubbliche o di interesse generale.

4.1.6. Casi di redditi elevati

Il nostro esempio precedente si applica alla maggior parte dei dipendenti. Tuttavia, il calcolo dell'imposta è diverso per i redditi elevati.

4.1.6.1. Limite massimo alla riduzione del 10% sul reddito annuo

Nella maggior parte dei casi, il reddito imponibile viene calcolato utilizzando la formula: R = 0,9 × S, dove S è lo stipendio annuale. Questa è nota come riduzione del 10%. Tale riduzione è soggetta a un limite massimo. Nel 2019:

  • non può superare i 12.502 euro;
  • non può essere inferiore a 437 euro;

Consideriamo il caso di un dipendente non sposato, senza figli e con uno stipendio annuo di 200.000 euro:

  • la riduzione del 10% è pari a 200.000 euro > 12.502 euro. Il limite massimo è quindi fissato a 12.502 euro;

4.1.6.2. Limite del quoziente familiare

Consideriamo un caso in cui si applica il limite familiare menzionato nel paragrafo collegato. Prendiamo il caso di una coppia con tre figli e un reddito annuo di 100.000 euro. Ripassiamo i passaggi del calcolo:

  • La detrazione del 10% è pari a 10.000 euro < 12.502 euro. Il reddito imponibile R è quindi pari a 100.000 - 10.000 = 90.000 euro;
  • La coppia possiede nbParts = 2 + 0,5 * 2 + 1 = 4 quote;
  • il loro quoziente familiare è quindi QF = R / nbParts = 90.000 / 4 = 22.500 euro;
  • la loro imposta lorda I1 con figli è I1 = 0,14 × 90.000 – 1.394,96 × 4 = 7.020 euro;
  • la loro imposta lorda I2 senza figli:
    • QF = 90.000 / 2 = 45.000 euro;
    • I2 = 0,3 × 90.000 – 5.798 × 2 = 15.404 euro;
    • la regola del limite massimo del quoziente familiare stabilisce che il beneficio derivante dai figli non può superare (1.551 × 4 mezze quote) = 6.204 euro. Tuttavia, in questo caso, si ha I2 – I1 = 15.404 – 7.020 = 8.384 euro, che è superiore a 6.204 euro;
    • l'imposta lorda viene quindi ricalcolata come I3 = I2 - 6.204 = 15.404 - 6.204 = 9.200 euro;

Questa coppia non riceverà né un credito d'imposta né una riduzione, e la loro imposta finale sarà di 9.200 euro.

4.1.7. Dati ufficiali

Il calcolo dell'imposta è complesso. Nel corso di questo documento, verranno effettuati dei test utilizzando i seguenti esempi. I risultati provengono dal simulatore dell'autorità fiscale [https://www3.impots.gouv.fr/simulateur/calcul_impot/2019/simplifie/index.htm]:

Contribuente
Risultati ufficiali
Risultati dell'algoritmo del documento
Coppia con 2 figli e un reddito annuo di 55.555 euro
Imposta = 2.815 euro
Aliquota fiscale = 14%
Imposta = 2.814 euro
Aliquota fiscale = 14%
Coppia con 2 figli e un reddito annuo di 50.000 euro
Imposta = 1.385 euro
Credito d'imposta = 720 euro
Riduzione = 0 euro
Aliquota fiscale = 14%
Imposta = 1.384 euro
Detrazione = 384 euro
Credito = 347 euro
Aliquota fiscale = 14%
Coppia con 3 figli e un reddito annuo di 50.000 euro
Imposta = 0 euro
Credito d'imposta = 384 euro
Riduzione = 346 euro
Aliquota fiscale = 14%
Imposta = 0 euro
Sconto = 720 euro
Riduzione = 0 euro
Aliquota fiscale = 14%
Single con 2 figli e un reddito annuo di 100.000 euro
Imposta = 19.884 euro
Credito d'imposta = 0 euro
Detrazione = 0 euro
Aliquota fiscale = 41%
Imposta = 19.884 euro
Sovrattassa = 4.480 euro
Sconto = 0 euro
Riduzione = 0 euro
Aliquota fiscale = 41%
Single con 3 figli e un reddito annuo di 100.000 euro
Imposta = 16.782 euro
Credito d'imposta = 0 euro
Detrazione = 0 euro
Aliquota fiscale = 41%
Imposta = 16.782 euro
Sovrattassa = 7.176 euro
Sconto = 0 euro
Riduzione = 0 euro
Aliquota fiscale = 41%
Coppia con tre figli e un reddito annuo di 100.000 euro
Imposta = 9.200 euro
Credito d'imposta = 0 euro
Detrazione = 0 euro
Aliquota fiscale = 30%
Imposta = 9.200 euro
Sovrattassa = 2.180 euro
Sconto = 0 euro
Riduzione = 0 euro
Aliquota fiscale = 30%
Coppia con 5 figli e un reddito annuo di 100.000 euro
Imposta = 4.230 euro
Credito d'imposta = 0 euro
Detrazione = 0 euro
Aliquota fiscale = 14%
Imposta = 4.230
Detrazione = 0 euro
Detrazione = 0 euro
Aliquota fiscale = 14%
Celibe, senza figli e reddito annuo di 100.000 euro
Imposta = 22.986 euro
Credito d'imposta = 0 euro
Detrazione = 0 euro
Aliquota fiscale = 41%
Imposta = 22.986 euro
Sovrattassa = 0 euro
Sconto = 0 euro
Riduzione = 0 euro
Aliquota fiscale = 41%
Coppia con 2 figli e un reddito annuo di 30.000 euro
Imposta = 0 euro
Credito d'imposta = 0 euro
Detrazione = 0 euro
Aliquota fiscale = 0%
Imposta = 0 euro
Sconto = 0 euro
Detrazione = 0 euro
Aliquota fiscale = 0%
Celibe, senza figli e reddito annuo di 200.000 euro
Imposta = 64.211 euro
Credito d'imposta = 0 euro
Detrazione = 0 euro
Aliquota fiscale = 45%
Imposta = 64.210 euro
Sovrattassa = 7.498 euro
Sconto = 0 euro
Riduzione = 0 euro
Aliquota fiscale = 45%
Coppia con 3 figli e un reddito annuo di 200.000 euro
Imposta = 42.843 euro
Credito d'imposta = 0 euro
Detrazione = 0 euro
Aliquota fiscale = 41%
Imposta = 42.842 euro
Sovrattassa = 17.283 euro
Sconto = 0 euro
Riduzione = 0 euro
Aliquota fiscale = 41%

Nell'esempio sopra riportato, il termine "sovrattassa" si riferisce all'importo aggiuntivo pagato dai redditi più elevati a causa di due fattori:

  • il limite massimo del 10% sulla detrazione dal reddito annuo;
  • il limite massimo dell'assegno familiare;

Questo indicatore non ha potuto essere verificato poiché il simulatore dell’autorità fiscale non lo fornisce.

Si può notare che l’algoritmo del documento calcola ogni volta l’importo corretto dell’imposta, sebbene con un margine di errore di 1 euro. Questo margine di errore deriva dall’arrotondamento. Tutti gli importi monetari vengono arrotondati per eccesso all’euro più vicino in alcuni casi e per difetto all’euro più vicino in altri. Poiché non conoscevo le regole ufficiali, gli importi monetari nell’algoritmo del documento sono stati arrotondati:

  • per arrotondamento per eccesso all'euro successivo per sconti e riduzioni;
  • per difetto all'euro più vicino per i supplementi e l'imposta finale;

Nella sezione seguente, verranno condotti dei test per verificare la validità dei risultati. Verranno eseguiti utilizzando gli esempi della tabella precedente con un margine di errore accettato di 1 euro.

4.2. Struttura della directory dello script

Image

4.3. Versione 1

4.3.1. L'algoritmo

Presentiamo un programma iniziale in cui:

  • i dati necessari per calcolare l'imposta sono hard-coded nel programma come array e costanti;
  • i dati del contribuente (stato civile, figli, stipendio) sono memorizzati in un primo file di testo [taxpayersdata.txt];
  • i risultati del calcolo dell'imposta (stato civile, figli, stipendio, imposta) sono memorizzati in un secondo file di testo [resultats.txt];

Lo script [version-01/main.php] è il seguente:


<?php
 
// strict types for function parameters
declare(strict_types=1);
 
// global constants
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);
 
// definition of local constants
$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);
 
// 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
  $result = calculImpot($marié, (int) $enfants, (float) $salaire, $limites, $coeffR, $coeffN);
  // enter the result in the results file
  $result = ["marié" => $marié, "enfants" => $enfants, "salaire" => $salaire] + $result;
  fputs($résultats, \json_encode($result, JSON_UNESCAPED_UNICODE) . "\n");
  // following data
}
// close files
fclose($data);
fclose($résultats);
 
// end
exit;
 
// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne): string {
  // 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);
}
 
// tAX CALCULATION
// --------------------------------------------------------------------------
function calculImpot(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {

  // result
  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 {

  // result
  return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}
 
// revenuImposable=annualwage-discount
// the allowance has a minimum and a maximum
function getRevenuImposable(float $salaire): float {

  // result
  return floor($revenuImposable);
}
 
// calculates any discount
function getDecote(string $marié, float $salaire, float $impots): float {

  // result
  return ceil($décôte);
}
 
// calculates any reduction
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {
  /
  // result
  return ceil($réduction);
}

Il file di dati taxpayersdata.txt (stato civile, figli, stipendio):

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

Il file results.txt (stato civile, figli, stipendio, imposta, sovrattassa, sconto, riduzione, aliquota fiscale) dei risultati ottenuti:

{"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}

Commenti

  • riga 4: imponiamo il rigoroso rispetto del tipo dei parametri della funzione;
  • righe 7–16: definizione di tutte le costanti necessarie per il calcolo dell'imposta;
  • riga 19: il nome del file di testo contenente i dati del contribuente (stato civile, figli, stipendio);
  • riga 20: il nome del file di testo contenente i risultati (stato civile, figli, stipendio, imposta) del calcolo delle imposte;
  • righe 21–23: i tre array di dati che definiscono le diverse fasce di imposta per il calcolo delle imposte;
  • righe 26–30: aprono il file dei dati del contribuente in lettura [r]. La funzione [fopen] restituisce il valore booleano FALSE se il file non può essere aperto;
  • righe 33–37: aprono il file dei risultati in modalità scrittura [w];
  • righe 40–51: ciclo per leggere le righe (coniuge, figli, reddito) dal file dei dati del contribuente;
  • riga 40: la funzione [fgets] legge 100 caratteri e si ferma al primo carattere di fine riga incontrato. In questo caso, tutte le righe hanno una lunghezza inferiore a 100 caratteri. Se viene incontrato un carattere di fine riga, questo viene incluso nella stringa restituita. Quando viene raggiunta la fine del file, la funzione [fgets] restituisce FALSE;
  • riga 42: il carattere di fine riga viene rimosso;
  • riga 44: vengono recuperati i componenti (stato civile, figli, stipendio) della riga;
  • riga 46: viene calcolata l'imposta. Il risultato viene restituito come array associativo (riga 76);
  • riga 48: le chiavi [married, children, salary] vengono aggiunte all'array precedentemente recuperato;
  • riga 49: il risultato viene memorizzato nel file dei risultati come stringa JSON;
  • righe 53–54: una volta che il file dei dati del contribuente è stato completamente elaborato, i file vengono chiusi;
  • riga 60: la funzione che rimuove l'interruzione di riga da una riga $line. L'interruzione di riga è la stringa "\r\n" sui sistemi Windows, "\n" sui sistemi Unix. Il risultato è la stringa di input senza l'interruzione di riga.
  • righe 63-64: substr($string, $start, $size) è la sottostringa di $string che inizia dal carattere $start e contiene al massimo $size caratteri;

La funzione [calculImpot] è la seguente:


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

// calcul de l'impôt
// --------------------------------------------------------------------------
function calculImpot(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
  // $marié : oui, non
  // $enfants : nombre d'enfants
  // $salaire : salaire annuel
  // $limites, $coeffR, $coeffN : les tableaux des données permettant le calcul de l'impôt
  //
  // calcul de l'impôt avec enfants
  $result1 = calculImpot2($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
  $impot1 = $result1["impôt"];
  // calcul de l'impôt sans les enfants
  if ($enfants != 0) {
    $result2 = calculImpot2($marié, 0, $salaire, $limites, $coeffR, $coeffN);
    $impot2 = $result2["impôt"];
    // application du plafonnement du quotient familial
    if ($enfants < 3) {
      // $PLAFOND_QF_DEMI_PART euros pour les 2 premiers enfants
      $impot2 = $impot2 - $enfants * PLAFOND_QF_DEMI_PART;
    } else {
      // $PLAFOND_QF_DEMI_PART euros pour les 2 premiers enfants, le double pour les suivants
      $impot2 = $impot2 - 2 * PLAFOND_QF_DEMI_PART - ($enfants - 2) * 2 * PLAFOND_QF_DEMI_PART;
    }
  } else {
    $impot2 = $impot1;
    $result2 = $result1;
  }
  // on prend l'impôt le plus fort avec le taux et la surcôte qui vont avec
  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"];
  }
  // calcul d'une éventuelle décôte
  $décôte = getDecote($marié, $salaire, $impot);
  $impot -= $décôte;
  // calcul d'une éventuelle réduction d'impôts
  $réduction = getRéduction($marié, $salaire, $enfants, $impot);
  $impot -= $réduction;
  // résultat
  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 {

  // résultat
  return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}
 
// revenuImposable=salaireAnnuel-abattement
// l'abattement de 10 % a un min et un max
function getRevenuImposable(float $salaire): float {

}
 
// calcule une décôte éventuelle
function getDecote(string $marié, float $salaire, float $impots): float {

  // résultat
  return ceil($décôte);
}
 
// calcule une réduction éventuelle
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {

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

Commenti

  • Riga 10: L'imposta lorda viene calcolata includendo i figli. Il risultato viene restituito nella forma ["tax" => $tax, "surcharge" => $surcharge, "rate" => $coeffR[$i]] dove:
    • [‘tax’]: l’imposta lorda;
    • [‘surcharge’]: l’importo della sovrattassa, se presente. Questa si applica quando la detrazione del 10% supera la soglia di 12.502 euro;
    • [‘rate’]: l’aliquota fiscale del contribuente;
  • riga 11: l’imposta lorda [impot1] dovuta;
  • righe 13–14: se il contribuente ha almeno un figlio, il calcolo dell’imposta viene rifatto utilizzando gli stessi dati ma con 0 figli. Questo secondo calcolo è necessario per determinare se la riduzione prevista per i figli (nbParts*coeffN) supera una certa soglia;
  • riga 15: l’imposta lorda [impot2] dovuta;
  • righe 16–23: per l'imposta lorda [impot2], ora si tiene conto dei figli: ogni quota di 1/2 fornita dai figli consente una riduzione di [PLAFOND_QF_DEMI_PART] euro;
  • righe 25–26: caso in cui il contribuente non abbia figli. In questo caso, il calcolo di [impot2] non è necessario. È pari a [impot1];
  • righe 29–37: sono state calcolate due imposte lorde [impot1, impot2]. L'autorità fiscale mantiene la più alta delle due. Ciò produce un'imposta lorda [impot];
  • righe 39–40: l'importo lordo [tax] può essere soggetto a una riduzione;
  • righe 42–43: l'importo lordo [impot] può essere soggetto a una riduzione;
  • riga 45: [tax] è ora l'imposta netta dovuta. Vengono restituiti i risultati;

La funzione [calculImpot2] è la seguente:


// --------------------------------------------------------------------------
function calculImpot2(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
  // $marié : oui, non
  // $enfants : nombre d'enfants
  // $salaire : salaire annuel
  // $limites, $coeffR, $coeffN : les tableaux des données permettant le calcul de l'impôt
  //
  // nombre de parts
  $marié = strtolower($marié);
  if ($marié === "oui") {
    $nbParts = $enfants / 2 + 2;
  } else {
    $nbParts = $enfants / 2 + 1;
  }
  // 1 part par enfant à partir du 3e
  if ($enfants >= 3) {
    // une demi-part de + pour chaque enfant à partir du 3e
    $nbParts += 0.5 * ($enfants - 2);
  }
  // revenu imposable
  $revenuImposable = getRevenuImposable($salaire);
  // surcôte
  $surcôte = floor($revenuImposable - 0.9 * $salaire);
  // pour des pbs d'arrondi
  if ($surcôte < 0) {
    $surcôte = 0;
  }
  // quotient familial
  $quotient = $revenuImposable / $nbParts;
  // est mis à la fin du tableau limites pour arrêter la boucle qui suit
  $limites[count($limites) - 1] = $quotient;
  // calcul de l'impôt
  $i = 0;
  while ($quotient > $limites[$i]) {
    $i++;
  }
  // du fait qu'on a placé $quotient à la fin du tableau $limites, la boucle précédente
  // ne peut déborder du tableau $limites
  // maintenant on peut calculer l'impôt
  $impôt = floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
  // résultat
  return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}
 
// revenuImposable=salaireAnnuel-abattement
// l'abattement a un min et un max
function getRevenuImposable(float $salaire): float {
  
  // résultat
  return floor($revenuImposable);
}
 

Commenti

  • Qui applichiamo il calcolo dell'imposta utilizzando l'aliquota progressiva;
  • riga 9: strtolower($string) converte $string in minuscolo;
  • righe 10–19: calcolo del numero di quote del contribuente;
  • riga 21: calcoliamo il reddito imponibile utilizzando una funzione. Infatti, abbiamo visto che non è sempre 0,9*RedditoAnnuale. La detrazione del 10% è infatti limitata a 12.502 euro;
  • riga 23: calcola la potenziale sovrattassa se il reddito imponibile è superiore a 0,9*redditoAnnuo;
  • righe 25–27: corregge il fatto che, a causa di errori di arrotondamento, a volte si ha [$surcharge=-1];
  • riga 29: il quoziente familiare;
  • righe 30–36: questo quoziente viene utilizzato per determinare la fascia di imposta del contribuente;
  • riga 40: una volta determinata la fascia di imposta del contribuente, è possibile calcolare l'imposta lorda. La funzione floor($x) restituisce il numero intero immediatamente inferiore a [$x];
  • riga 42: vengono restituite le informazioni calcolate;

La funzione [getRevenuImposable] è la seguente:


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

// revenuImposable=salaireAnnuel-abattement
// l'abattement a un min et un max
function getRevenuImposable(float $salaire): float {
  // abattement de 10% du salaire
  $abattement = 0.1 * $salaire;
  // cet abattement ne peut dépasser ABATTEMENT_DIXPOURCENT_MAX
  if ($abattement > ABATTEMENT_DIXPOURCENT_MAX) {
    $abattement = ABATTEMENT_DIXPOURCENT_MAX;
  }
  // l'abattement ne peut être inférieur à ABATTEMENT_DIXPOURCENT_MIN
  if ($abattement < ABATTEMENT_DIXPOURCENT_MIN) {
    $abattement = ABATTEMENT_DIXPOURCENT_MIN;
  }
  // revenu imposable
  $revenuImposable = $salaire - $abattement;
  // résultat
  return floor($revenuImposable);
}

Commenti

  • riga 5: la detrazione forfettaria è pari al 10% dello stipendio annuo;
  • righe 7–9: la detrazione non può superare la detrazione massima [ABATTEMENT_DIXPOURCENT_MAX];
  • righe 10–13: la detrazione non può essere inferiore alla detrazione minima [ABATTEMENT_DIXPOURCENT_MIN];
  • riga 15: calcolo del reddito imponibile;

La funzione [getDecote] è la seguente:


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

// calcule une décôte éventuelle
function getDecote(string $marié, float $salaire, float $impots): float {
  // au départ, une décôt nulle
  $décôte = 0;
  // montant maximal d'tax to get the discount
  $plafondImpôtPourDécôte = $marié === "oui" ? PLAFOND_IMPOT_COUPLE_POUR_DECOTE : PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE;
  if ($impots < $plafondImpôtPourDécôte) {
    // montant maximal de la décôte
    $plafondDécôte = $marié === "oui" ? PLAFOND_DECOTE_COUPLE : PLAFOND_DECOTE_CELIBATAIRE;
    // décôte théorique
    $décôte = $plafondDécôte - 0.75 * $impots;
    // la décôte ne peut dépasser le montant de l'tax
    if ($décôte > $impots) {
      $décôte = $impots;
    }
    // pas de décôte <0
    if ($décôte < 0) {
      $décôte = 0;
    }
  }
  // résultat
  return ceil($décôte);
}

Commenti

  • riga 6: importo lordo massimo dell'imposta per beneficiare di una riduzione fiscale. Tale importo varia a seconda che si tratti di persone single o di coppie;
  • riga 7: se il contribuente ha diritto alla riduzione fiscale;
  • riga 11: la formula del credito d'imposta. [taxCreditCap] è l'importo massimo del credito d'imposta. Questo importo massimo è calcolato alla riga 9. Anche in questo caso, dipende dallo stato civile del contribuente: coniugato o single;
  • righe 13–15: la detrazione non può superare l'imposta lorda dovuta. Questo è il caso, ad esempio, se [taxes] è 0 alla riga 11;
  • righe 17–19: per evitare l'arrotondamento a -1;

La funzione [getReduction] è la seguente:


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

// calcule une réduction éventuelle
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {
  // le plafond des revenus pour avoir droit à la réduction 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;
  }
  // revenu imposable
  $revenuImposable = getRevenuImposable($salaire);
  // réduction
  $réduction = 0;
  if ($revenuImposable < $plafondRevenuPourRéduction) {
    // réduction de 20%
    $réduction = 0.2 * $impots;
  }
  // résultat
  return ceil($réduction);
}

Commenti

  • righe 4–10: per avere diritto a una riduzione fiscale, il reddito imponibile (riga 10) deve essere inferiore a una soglia calcolata nelle righe 4–8;
  • righe 13–16: se le condizioni sono soddisfatte, il contribuente ha diritto a una riduzione fiscale del 20% (riga 15);

4.3.2. Risultati

Il file di dati taxpayersdata.txt (stato civile, figli, stipendio):

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

Il file results.txt (stato civile, figli, stipendio, imposta, sovrattassa, sconto, riduzione, aliquota fiscale) dei risultati ottenuti:

{"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}

I risultati ottenuti sono coerenti con quelli ottenuti utilizzando il simulatore dell'agenzia delle entrate.

4.3.3. Conclusione

L'algoritmo di calcolo delle imposte, anche nei casi considerati semplici, è complesso. Non lo riprenderemo qui. Tra le diverse versioni, il suo nucleo rimarrà lo stesso nonostante alcune modifiche nella presentazione. Commenteremo quindi solo queste ultime.

4.4. Versione 2

4.4.1. Modifiche

Nella versione precedente, i dati necessari per il calcolo dell'imposta erano hard-coded come costanti e array. Questo metodo dovrebbe essere evitato. Nella nuova versione, questi dati sono esternalizzati in un file JSON:

Image

Il contenuto del file [taxadmindata.json] è il seguente:


{
    "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
}

La nuova versione [version-02/main.php] è la seguente:


<?php
 
// strict adherence to declared function parameter types
declare (strict_types=1);
 
// definition of constants
$TAXPAYERSDATA = "taxpayersdata.txt";
$RESULTATS = "resultats.txt";
$TAXADMINDATA = "taxadmindata.json";
 
// retrieve the contents of the tax data file
$fileContents = \file_get_contents($TAXADMINDATA);
$erreur = FALSE;
// mistake?
if (!$fileContents) {
  // we note the error
  $erreur = TRUE;
  $message = "Le fichier des données [$TAXADMINDATA] n'existe pas";
}
 
if (!$erreur) {
  // retrieve the jSON code from the configuration file in an associative array
  $taxAdminData = \json_decode($fileContents, true);
  // mistake?
  if (!$taxAdminData) {
    // we note the error
    $erreur = TRUE;
    $message = "Le fichier de données jSON [$TAXADMINDATA] n'a pu être exploité correctement";
  }
}
 
// mistake?
if ($erreur) {
  print "$message\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";
  // output
  exit;
}
 
// opening taxpayer data file
$taxpayersdata = fopen($TAXPAYERSDATA, "r");
if (!$taxpayersdata) {
  print "Impossible d'ouvrir le fichier des contribuables [$TAXPAYERSDATA]\n";
  // output
  exit;
}
 
// use the current line of the data file
while ($ligne = fgets($taxpayersdata, 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
  $result = calculImpot($taxAdminData, $marié, (int) $enfants, (int) $salaire);
  // enter the result in the results file
  $result = ["marié" => $marié, "enfants" => $enfants, "salaire" => $salaire] + $result;
  fputs($résultats, \json_encode($result, JSON_UNESCAPED_UNICODE) . "\n");
  // following data
}
// close files
fclose($taxpayersdata);
fclose($résultats);
 
// end
exit;
 
// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne) {

  // end
  return($ligne);
}
 
// tAX CALCULATION
// --------------------------------------------------------------------------
function calculImpot(array $taxAdminData, string $marié, int $enfants, float $salaire) {
  // $marié : yes, no
  // $enfants : number of children
  // $salaire: annual salary
  // $taxAdminData: tax administration data
  //
  // tax calculation with children
  $result1 = calculImpot2($taxAdminData, $marié, $enfants, $salaire);
  $impot1 = $result1["impôt"];
  // tax calculation without children
  if ($enfants != 0) {
    $result2 = calculImpot2($taxAdminData, $marié, 0, $salaire);
    $impot2 = $result2["impôt"];
    // application of the family allowance ceiling
    if ($enfants < 3) {
      // $PLAFOND_QF_DEMI_PART euros for the first 2 children
      $impot2 = $impot2 - $enfants * $taxAdminData["PLAFOND_QF_DEMI_PART"];
    } else {
      // $PLAFOND_QF_DEMI_PART euros for the first 2 children, double for subsequent children
      $impot2 = $impot2 - 2 * $taxAdminData["PLAFOND_QF_DEMI_PART"] - ($enfants - 2) * 2 * $taxAdminData["PLAFOND_QF_DEMI_PART"];
    }
  } else {
    $impot2 = $impot1;
    $result2 = $result1;
  }
  // we take the highest tax with the rate and surcharge that go with it
  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"];
  }
  // calculation of any discount
  $décôte = getDecote($taxAdminData, $marié, $salaire, $impot);
  $impot -= $décôte;
  // calculation of any tax reduction
  $réduction = getRéduction($taxAdminData, $marié, $salaire, $enfants, $impot);
  $impot -= $réduction;
  // result
  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é : yes, no

  // result
  return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}
 
// revenuImposable=annualwage-discount
// the allowance has a minimum and a maximum
function getRevenuImposable(array $taxAdminData, float $salaire): float {

  // result
  return floor($revenuImposable);
}
 
// calculates any discount
function getDecote(array $taxAdminData, string $marié, float $salaire, float $impots): float {

  // result
  return ceil($décôte);
}
 
// calculates any reduction
function getRéduction(array $taxAdminData, string $marié, float $salaire, int $enfants, float $impots): float {

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

Commenti

  • righe 11–19: si tenta di leggere il contenuto del file JSON denominato [TAXADMINDATA];
  • righe 21–30: se il file JSON è stato letto correttamente, il suo contenuto viene decodificato nell'array associativo [$taxAdminData];
  • righe 32–36: se si è verificato un errore in una delle due operazioni precedenti, viene visualizzato un messaggio di errore sulla console e il programma si interrompe;
  • La differenza rispetto alla versione 01 è che qui i dati dell'amministrazione fiscale (array e costanti) sono memorizzati nell'array associativo [$taxAdminData], mentre nella versione 01 erano memorizzati in array e costanti globali. È la natura globale di queste costanti che distingue le due versioni:
    • nella versione 01, le costanti erano note in tutte le funzioni di [main.php];
    • per ottenere lo stesso risultato nella versione 02, l'array associativo [$taxAdminData] deve essere passato come parametro a tutte le funzioni (righe 83, 129, 138, 145, 152);
  • ogni funzione nella versione 02 deve utilizzare il contenuto dell'array [$taxAdminData];
  • Righe 83–126: nella funzione [calculateTax], dove in precedenza venivano utilizzate costanti globali o gli array [limits, coeffR, coeffN], ora utilizziamo il contenuto dell'array [$taxAdminData] passato come parametro (righe 99, 102);
  • Tutte le altre funzioni vengono riscritte allo stesso modo;

I risultati ottenuti sono gli stessi di quelli ottenuti nella versione precedente.

4.4.2. Conclusione

La versione 02 è molto più flessibile della versione 01. Nel 2020, l'algoritmo di calcolo delle imposte sarà probabilmente lo stesso del 2019. Cambieranno solo le fasce di imposta e le costanti di calcolo. Sarà quindi sufficiente aggiornare il file [taxadmindata.json]. Con la versione 01, è necessario intervenire sul codice per modificare le fasce di imposta e le costanti di calcolo. Tuttavia, è probabile che le persone che devono modificare i valori delle fasce di imposta e delle costanti di calcolo non abbiano accesso al codice dell'algoritmo.