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 abbia da dichiarare solo il proprio stipendio. Come indicato nella nota (1), l’imposta così calcolata è l’imposta al lordo di tre meccanismi:

  • il tetto massimo del quoziente familiare, che si applica ai redditi elevati;
  • la detrazione e la riduzione d’imposta che si applicano ai redditi bassi;

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

Image

Ci proponiamo di scrivere un programma che consenta di calcolare l’imposta di un contribuente nel caso semplificato di un contribuente che abbia da dichiarare solo il proprio stipendio:

4.1.1. Calcolo dell’imposta lorda

L'imposta lorda può essere calcolata come segue:

Si calcola innanzitutto il numero di quote del contribuente:

    • ogni genitore apporta 1 quota;
    • i primi due figli apportano ciascuno 1/2 quota;
    • i figli successivi apportano una quota ciascuno:

Il numero di quote è quindi:

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

dove nbEnfants è il numero dei suoi figli;

  • si calcola il reddito imponibile R=0,9*S dove S è lo stipendio annuale;
  • si calcola il quoziente familiare QF = R / nbParts;
  • si calcola l’imposta lorda I in base ai seguenti dati (2019):
9964
0
0
27519
0,14
1394,96
73779
0,3
5798
156.244
0,41
13913,69
0
0,45
20163,45

Ogni riga presenta 3 campi: champ1, champ2, champ3. Per calcolare l'imposta I, si cerca la prima riga in cui QF ≤ campo1 e si prendono i valori di 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=45000

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*nbParts=[0,14*45000-1394,96*3]=2115. L’imposta viene arrotondata all’euro inferiore.

Se la relazione QF ≤ campo1 è vera fin dalla prima riga, allora l’imposta è pari a zero.

Se QF è tale che la relazione QF<=campo1 non è mai soddisfatta, allora vengono utilizzati i coefficienti dell’ultima riga. In questo caso:

    0            0.45        20163.45

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

4.1.2. Limite massimo del quoziente familiare

Image

Per verificare se si applica il limite massimo del quoziente familiare QF, si ricalcola l’imposta lorda senza considerare i figli. Sempre per il lavoratore 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=45000/2=22500

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*nbParts=[0,14*45000-1394,96*2]=3510.

Guadagno massimo legato ai figli: 1551 * 2 = 3102 euro

Imposta minima: 3510 – 3102 = 408 euro

L’imposta lorda con 3 quote, già calcolata pari a 2115 euro, è superiore all’imposta minima di 408 euro, pertanto in questo caso non si applica il limite massimo familiare.

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

  • [impôt1]: è l’imposta lorda calcolata con i figli;
  • [impôt2]: è l’imposta lorda calcolata senza i figli e ridotta del guadagno massimo (in questo caso 1551 euro per mezza quota) relativo ai figli;

4.1.3. Calcolo della riduzione

Image

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

L’imposta lorda (2115) risultante dalla fase precedente è inferiore a 2627 euro per una coppia (1595 euro per un celibe): si applica quindi la riduzione. Essa si ottiene con il seguente calcolo:

riduzione = soglia (coppia = 1970 / single = 1196) - 0,75 * imposta lorda

riduzione = 1970 - 0,75 * 2115 = 383,75 arrotondato a 384 euro.

Nuova imposta lorda = 2115 - 384 = 1731 euro

4.1.4. Calcolo della riduzione d’imposta

Image

Al di sotto di una certa soglia, viene applicata una riduzione del 20% sull’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 errata);

Questa soglia viene aumentata del valore: 3.797 * (numero di mezze quote apportate dai figli).

Sempre per il lavoratore 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: 1731 * 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 si ferma qui: l’imposta netta da pagare sarà di 1384 euro. In realtà, il contribuente può beneficiare di altre riduzioni, in particolare per le donazioni a enti di interesse pubblico o generale.

4.1.6. Caso dei redditi elevati

Il nostro esempio precedente corrisponde alla maggior parte dei casi dei lavoratori dipendenti. Tuttavia, il calcolo dell’imposta è diverso nel caso dei redditi elevati.

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

Nella maggior parte dei casi, il reddito imponibile si ottiene con la formula: R=0,9*S, dove S è lo stipendio annuale. Si parla in questo caso di 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;

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

  • la riduzione del 10% è pari a 20.000 euro > 12.502 euro. Viene quindi ridotta a 12.502 euro;

4.1.6.2. Limite massimo del quoziente familiare

Consideriamo un caso in cui si applica il limite massimo del quoziente familiare indicato nel paragrafo di riferimento. Prendiamo il caso di una coppia con tre figli e un reddito annuo di 100.000 euro. Ripassiamo le fasi del calcolo:

  • la detrazione del 10% è pari a 10.000 euro < 12.502 euro. Il reddito imponibile R è quindi 100.000 - 10.000 = 90.000 euro;
  • la coppia ha nbParts = 2 + 0,5 × 2 + 1 = 4 quote;
  • il suo quoziente familiare è quindi QF = R / nbParts = 90.000 / 4 = 22.500 euro;
  • la sua imposta lorda I1 con figli è pari a I1=0,14*90.000-1.394,96*4= 7.020 euro;
  • la sua 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 possa superare (1551*4 mezze quote)=6204 euro. In questo caso, invece, è pari a I2-I1=15404-7020= 8384 euro, quindi superiore a 6204 euro;
    • l’imposta lorda viene quindi ricalcolata come I3 = I2-6204 = 15.404 - 6.204 = 9.200 euro;

Questa coppia non beneficerà né di uno sconto né di una riduzione e la sua imposta finale sarà di 9200 euro.

4.1.7. Dati ufficiali

Il calcolo dell’imposta è complesso. Nel corso del documento, le verifiche saranno effettuate utilizzando i seguenti esempi. I risultati provengono dal simulatore dell’amministrazione 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 55555 euro
Imposta = 2815 euro
Aliquota fiscale = 14 %
Imposta = 2814 euro
Aliquota fiscale = 14 %
Coppia con 2 figli e un reddito annuo di 50.000 euro
Imposta = 1.385 euro
Sconto = 720 euro
Riduzione = 0 euro
Aliquota fiscale = 14 %
Imposta = 1.384 euro
Sconto = 384 euro
Sconto = 347 euro
Aliquota fiscale = 14 %
Coppia con 3 figli e un reddito annuo di 50.000 euro
Imposta = 0 euro
Sconto = 384 euro
Sconto = 346 euro
Aliquota fiscale = 14 %
Imposta = 0 euro
Sconto = 720 euro
Riduzione = 0 euro
Aliquota fiscale = 14 %
Celibe con 2 figli e un reddito annuo di 100.000 euro
Imposta = 19.884 euro
Sconto = 0 euro
Sconto = 0 euro
Aliquota fiscale = 41 %
Imposta = 19.884 euro
Sovrattassa = 4.480 euro
Sconto = 0 euro
Riduzione = 0 euro
Aliquota fiscale = 41 %
Celibe con 3 figli e un reddito annuo di 100.000 euro
Imposta = 16.782 euro
Sconto = 0 euro
Sconto = 0 euro
Aliquota fiscale = 41 %
Imposta = 16.782 euro
Sovrattassa = 7.176 euro
Sconto = 0 euro
Riduzione = 0 euro
Aliquota fiscale = 41 %
Coppia con 3 figli e un reddito annuo di 100.000 euro
Imposta = 9.200 euro
Sconto = 0 euro
Riduzione = 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
Sconto = 0 euro
Sconto = 0 euro
Aliquota fiscale = 14 %
Imposta = 4.230 euro
Sconto = 0 euro
Sconto = 0 euro
Aliquota fiscale = 14 %
Celibe senza figli e con un reddito annuo di 100.000 euro
Imposta = 22.986 euro
Sconto = 0 euro
Sconto = 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
Sconto = 0 euro
Sconto = 0 euro
Aliquota fiscale = 0%
Imposta = 0 euro
Sconto = 0 euro
Riduzione = 0 euro
Aliquota fiscale = 0 %
Celibe senza figli e con un reddito annuo di 200.000 euro
Imposta = 64.211 euro
Sconto = 0 euro
Sconto = 0 euro
Aliquota fiscale = 45 %
Imposta = 64.210 euro
Maggiorazione = 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
Sconto = 0 euro
Sconto = 0 euro
Aliquota fiscale = 41%
Imposta = 42.842 euro
Maggiorazione = 17.283 euro
Sconto = 0 euro
Riduzione = 0 euro
Aliquota fiscale = 41 %

In questo caso, per «sovrattassa» si intende l’importo aggiuntivo che i redditi elevati devono versare a causa di due fenomeni:

  • il limite massimo del 10% sulla detrazione sui redditi annuali;
  • il limite massimo del quoziente familiare;

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

Si nota che l’algoritmo del documento fornisce ogni volta un’imposta corretta, con tuttavia un margine di errore di 1 euro. Questo margine di errore deriva dagli arrotondamenti. Tutte le somme di denaro vengono arrotondate a volte all’euro superiore, a volte all’euro inferiore. Poiché non conoscevo le regole ufficiali, gli importi dell’algoritmo del documento sono stati arrotondati:

  • all’euro superiore per gli sconti e le riduzioni;
  • all’euro inferiore per i sovrapprezzi e l’imposta finale;

In seguito, verranno effettuati dei test per verificare la validità dei risultati. Saranno condotti utilizzando gli esempi della tabella precedente con un margine di errore accettabile di 1 euro.

4.2. L’albero degli script

Image

4.3. Versione 1

4.3.1. L'algoritmo

Presentiamo un primo programma in cui:

  • i dati necessari al calcolo dell'imposta sono hardcoded nel codice sotto forma di tabelle e costanti;
  • i dati dei contribuenti (stato civile, figli, stipendio) si trovano 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

// tipi rigorosi per i parametri delle funzioni
declare(strict_types=1);

// costanti globali
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);

// definizione delle costanti locali
$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);

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

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

// elaborazione della riga corrente del file dei dati
while ($ligne = fgets($data, 100)) {
  // si rimuove l'eventuale carattere di fine riga
  $ligne = cutNewLineChar($ligne);
  // si recuperano i 3 campi coniuge:figli:stipendio che formano $ligne
  list($marié, $enfants, $salaire) = explode(",", $ligne);
  // si calcola l'imposta
  $result = calculImpot($marié, (int) $enfants, (float) $salaire, $limites, $coeffR, $coeffN);
  // si inserisce il risultato nel file dei risultati
  $result = ["marié" => $marié, "enfants" => $enfants, "salaire" => $salaire] + $result;
  fputs($résultats, \json_encode($result, JSON_UNESCAPED_UNICODE) . "\n");
  // dato successivo
}
// si chiudono i file
fclose($data);
fclose($résultats);

// fine
exit;

// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne): string {
  // si elimina il carattere di fine riga da $ligne, se presente
  $L = strlen($ligne);  // lunghezza riga
  while (substr($ligne, $L - 1, 1) === "\n" or substr($ligne, $L - 1, 1) === "\r") {
    $ligne = substr($ligne, 0, $L - 1);
    $L--;
  }
  // fine
  return($ligne);
}

// calcolo dell'imposta
// --------------------------------------------------------------------------
function calculImpot(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {

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

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

// revenuImposable=stipendioAnnuale-detrazione
// la detrazione ha un valore minimo e uno massimo
function getRevenuImposable(float $salaire): float {

  // risultato
  return floor($revenuImposable);
}

// calcola un'eventuale riduzione
function getDecote(string $marié, float $salaire, float $impots): float {

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

// calcola un'eventuale riduzione
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {
  /
  // risultato
  return ceil($réduction);
}

Il file dei dati taxpayersdata.txt (coniuge, 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

I file résultats.txt (stato civile, figli, stipendio, imposta, maggiorazione, 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: si impone il rigoroso rispetto del tipo dei parametri delle funzioni;
  • righe 7-16: definizione di tutte le costanti necessarie al calcolo dell’imposta;
  • riga 19: il nome del file di testo contenente i dati dei contribuenti (coniugato, figli, stipendio);
  • riga 20: il nome del file di testo contenente i risultati (stato civile, figli, stipendio, imposta) del calcolo dell'imposta;
  • righe 21-23: le tre tabelle di dati che definiscono le diverse fasce di imposta per il calcolo dell’imposta;
  • righe 26-30: apertura in lettura [r] del file dei dati dei contribuenti. La funzione [fopen] restituisce il valore booleano FALSE se l’apertura non è andata a buon fine;
  • righe 33-37: apertura in scrittura [w] del file dei risultati;
  • righe 40-51: ciclo di lettura delle righe (coniuge, figli, stipendio) del file dei dati dei contribuenti;
  • riga 40: la funzione [fgets] legge 100 caratteri e si interrompe al primo carattere di fine riga incontrato. In questo caso tutte le righe contengono meno di 100 caratteri. Se viene rilevato un carattere di fine riga, questo viene incluso nella stringa restituita. Quando viene raggiunta la fine del file, la funzione [fgets] restituisce il valore FALSE;
  • riga 42: il carattere di fine riga viene rimosso;
  • riga 44: vengono recuperate le componenti (coniuge, figli, stipendio) della riga;
  • riga 46: viene calcolata l’imposta. Il risultato viene restituito sotto forma di tabella associativa (riga 76);
  • riga 48: all'array recuperato in precedenza vengono aggiunte le chiavi [marié, enfants, salaire];
  • riga 49: il risultato viene memorizzato nel file dei risultati sotto forma di stringa jSON;
  • righe 53-54: una volta completata l’elaborazione del file dei dati dei contribuenti, i file vengono chiusi;
  • riga 60: la funzione che rimuove il carattere di fine riga da una riga $ligne. Il carattere di fine riga è la stringa "\r\n" sui sistemi Windows, "\n" sui sistemi Unix. Il risultato è la stringa di input senza il carattere di fine riga.
  • righe 63-64: substr($chaîne,$début,$taille) è la sottostringa di $chaîne che inizia dal carattere $début e contiene al massimo $taille caratteri;

La funzione [calculImpot] è la seguente:


// costanti globali
define("PLAFOND_QF_DEMI_PART", 1551);

// calcolo dell'imposta
// --------------------------------------------------------------------------
function calculImpot(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
  // $marié: sì, no
  // $enfants: numero di figli
  // $salaire: stipendio annuo
  // $limites, $coeffR, $coeffN: tabelle dei dati che consentono il calcolo dell'imposta
  //
  // calcolo dell'imposta con figli
  $result1 = calculImpot2($marié, $enfants, $salaire, $limites, $coeffR, $coeffN);
  $impot1 = $result1["impôt"];
  // calcolo dell'imposta senza figli
  if ($enfants != 0) {
    $result2 = calculImpot2($marié, 0, $salaire, $limites, $coeffR, $coeffN);
    $impot2 = $result2["impôt"];
    // applicazione del limite massimo del quoziente familiare
    if ($enfants < 3) {
      // $PLAFOND_QF_DEMI_PART euro per i primi 2 figli
      $impot2 = $impot2 - $enfants * PLAFOND_QF_DEMI_PART;
    } else {
      // $PLAFOND_QF_DEMI_PART euro per i primi 2 figli, il doppio per i successivi
      $impot2 = $impot2 - 2 * PLAFOND_QF_DEMI_PART - ($enfants - 2) * 2 * PLAFOND_QF_DEMI_PART;
    }
  } else {
    $impot2 = $impot1;
    $result2 = $result1;
  }
  // si considera l’imposta più elevata con l’aliquota e la maggiorazione corrispondenti
  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"];
  }
  // calcolo di un’eventuale riduzione
  $décôte = getDecote($marié, $salaire, $impot);
  $impot -= $décôte;
  // calcolo di un’eventuale riduzione delle imposte
  $réduction = getRéduction($marié, $salaire, $enfants, $impot);
  $impot -= $réduction;
  // risultato
  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 {

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

// revenuImposable=stipendioAnnuale-detrazione
// la detrazione del 10% ha un valore minimo e uno massimo
function getRevenuImposable(float $salaire): float {

}

// calcola un'eventuale riduzione
function getDecote(string $marié, float $salaire, float $impots): float {

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

// calcola un'eventuale riduzione
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {

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

Commenti

  • riga 10: l’imposta lorda viene calcolata includendo i figli. Si ottiene un risultato nella forma ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]] con:
    • [‘impôt’]: l’imposta lorda;
    • [‘surcôte’]: l’importo della maggiorazione, se presente. Questa si applica quando la detrazione del 10% supera la soglia di 12.502 euro;
    • [‘taux’]: l’aliquota fiscale del contribuente;
  • riga 11: l’imposta lorda da pagare [impot1];
  • righe 13-14: se il contribuente ha almeno un figlio, il calcolo dell’imposta viene ripetuto con gli stessi dati ma considerando 0 figli. Questo secondo calcolo è necessario per verificare se la riduzione derivante dai figli (nbParts*coeffN) è superiore a una determinata soglia;
  • riga 15: l’imposta lorda [impot2] da pagare;
  • righe 16-23: per l’imposta lorda [impot2], si tiene ora conto dei figli: ogni 1/2 quota derivante 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] è superfluo. È pari a [impot1];
  • righe 29-37: sono state calcolate due imposte lorde [impot1, impot2]. L’amministrazione fiscale prende in considerazione la più elevata delle due. Si ottiene un’imposta lorda [impot];
  • righe 39-40: l’importo lordo [impot] può essere soggetto a una riduzione;
  • righe 42-43: l’importo lordo [impot] può essere soggetto a una riduzione;
  • riga 45: [impot] è ora l’imposta netta da pagare. Si restituiscono i risultati;

La funzione [calculImpot2] è la seguente:


// --------------------------------------------------------------------------
function calculImpot2(string $marié, int $enfants, float $salaire, array $limites, array $coeffR, array $coeffN): array {
  // $marié: sì, no
  // $enfants: numero di figli
  // $salaire: stipendio annuo
  // $limites, $coeffR, $coeffN: tabelle dei dati che consentono il calcolo dell'imposta
  //
  // numero di quote
  $marié = strtolower($marié);
  if ($marié === "oui") {
    $nbParts = $enfants / 2 + 2;
  } else {
    $nbParts = $enfants / 2 + 1;
  }
  // 1 quota per ogni figlio a partire dal terzo
  if ($enfants >= 3) {
    // mezza quota in più per ogni figlio a partire dal terzo
    $nbParts += 0.5 * ($enfants - 2);
  }
  // reddito imponibile
  $revenuImposable = getRevenuImposable($salaire);
  // maggiorazione
  $surcôte = floor($revenuImposable - 0.9 * $salaire);
  // per problemi di arrotondamento
  if ($surcôte < 0) {
    $surcôte = 0;
  }
  // quoziente familiare
  $quotient = $revenuImposable / $nbParts;
  // viene inserito alla fine della tabella dei limiti per interrompere il ciclo successivo
  $limites[count($limites) - 1] = $quotient;
  // calcolo dell’imposta
  $i = 0;
  while ($quotient > $limites[$i]) {
    $i++;
  }
  // poiché $quotient è stato inserito alla fine della tabella $limites, il ciclo precedente
  // non può andare oltre i limiti della tabella $limites
  // ora è possibile calcolare l’imposta
  $impôt = floor($revenuImposable * $coeffR[$i] - $nbParts * $coeffN[$i]);
  // risultato
  return ["impôt" => $impôt, "surcôte" => $surcôte, "taux" => $coeffR[$i]];
}

// revenuImposable = stipendio annuo - detrazione
// la detrazione ha un valore minimo e uno massimo
function getRevenuImposable(float $salaire): float {
  
  // risultato
  return floor($revenuImposable);
}

Commenti

  • qui si applica il calcolo dell’imposta secondo la tabella progressiva;
  • riga 9: strtolower($chaîne) converte $chaîne in minuscolo;
  • righe 10-19: calcolo del numero di quote del contribuente;
  • riga 21: si calcola il reddito imponibile utilizzando una funzione. Infatti, abbiamo visto che non è sempre pari a 0,9*revenusAnnuels. La detrazione del 10% è infatti limitata a 12.502 euro;
  • riga 23: calcolo dell’eventuale maggiorazione se il reddito imponibile è superiore a 0,9*revenusAnnuels;
  • righe 25-27: corregge il fatto che, a causa di errori di arrotondamento, talvolta si ottiene [$surcôte=-1];
  • riga 29: il quoziente familiare;
  • righe 30-36: questo quoziente consente di individuare la fascia di imposta del contribuente;
  • riga 40: una volta individuata la fascia di imposta del contribuente, è possibile calcolare la sua imposta lorda. La funzione floor($x) restituisce il valore intero immediatamente inferiore a [$x];
  • riga 42: si restituiscono le informazioni calcolate;

La funzione [getRevenuImposable] è la seguente:


// costanti globali
define("ABATTEMENT_DIXPOURCENT_MAX", 12502);
define("ABATTEMENT_DIXPOURCENT_MIN", 437);

// revenuImposable=stipendioAnnuale-detrazione
// la detrazione ha un valore minimo e uno massimo
function getRevenuImposable(float $salaire): float {
  // detrazione pari al 10% dello stipendio
  $abattement = 0.1 * $salaire;
  // questa detrazione non può superare ABATTEMENT_DIXPOURCENT_MAX
  if ($abattement > ABATTEMENT_DIXPOURCENT_MAX) {
    $abattement = ABATTEMENT_DIXPOURCENT_MAX;
  }
  // la detrazione non può essere inferiore a ABATTEMENT_DIXPOURCENT_MIN
  if ($abattement < ABATTEMENT_DIXPOURCENT_MIN) {
    $abattement = ABATTEMENT_DIXPOURCENT_MIN;
  }
  // reddito imponibile
  $revenuImposable = $salaire - $abattement;
  // risultato
  return floor($revenuImposable);
}

Commenti

  • riga 5: la detrazione standard è pari al 10% dello stipendio annuale;
  • 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:


// costanti globali
define("PLAFOND_DECOTE_CELIBATAIRE", 1196);
define("PLAFOND_DECOTE_COUPLE", 1970);
define("PLAFOND_IMPOT_COUPLE_POUR_DECOTE", 2627);
define("PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE", 1595);

// calcola un eventuale sconto
function getDecote(string $marié, float $salaire, float $impots): float {
  // inizialmente, uno sconto pari a zero
  $décôte = 0;
  // importo massimo dell'imposta per ottenere la riduzione
  $plafondImpôtPourDécôte = $marié === "oui" ? PLAFOND_IMPOT_COUPLE_POUR_DECOTE : PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE;
  if ($impots < $plafondImpôtPourDécôte) {
    // importo massimo della riduzione
    $plafondDécôte = $marié === "oui" ? PLAFOND_DECOTE_COUPLE : PLAFOND_DECOTE_CELIBATAIRE;
    // sconto teorico
    $décôte = $plafondDécôte - 0.75 * $impots;
    // la riduzione non può superare l'importo dell'imposta
    if ($décôte > $impots) {
      $décôte = $impots;
    }
    // nessuna riduzione <0
    if ($décôte < 0) {
      $décôte = 0;
    }
  }
  // risultato
  return ceil($décôte);
}

Note

  • riga 6: importo massimo dell’imposta lorda per avere diritto a una riduzione. Tale importo varia a seconda che si tratti di persone single o di coppie;
  • riga 7: se il contribuente ha diritto alla riduzione;
  • riga 11: la formula della riduzione. [plafondDécôte] è l’importo massimo della riduzione. Tale importo massimo viene calcolato alla riga 9. Anche in questo caso dipende dalla situazione del contribuente, sposato o celibe;
  • righe 13-15: la detrazione non può essere superiore all’imposta lorda da pagare. Ciò si verifica, ad esempio, se [impots] è pari a 0 nella riga 11;
  • righe 17-19: per evitare un arrotondamento a -1;

La funzione [getRéduction] è la seguente:


// costanti globali
define("PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION", 21037);
define("PLAFOND_REVENUS_COUPLE_POUR_REDUCTION", 42074);
define("VALEUR_REDUC_DEMI_PART", 3797);

// calcola un'eventuale riduzione
function getRéduction(string $marié, float $salaire, int $enfants, float $impots): float {
  // il limite massimo di reddito per avere diritto alla riduzione del 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;
  }
  // reddito imponibile
  $revenuImposable = getRevenuImposable($salaire);
  // riduzione
  $réduction = 0;
  if ($revenuImposable < $plafondRevenuPourRéduction) {
    // riduzione del 20%
    $réduction = 0.2 * $impots;
  }
  // risultato
  return ceil($réduction);
}

Note

  • righe 4-10: per avere diritto a una riduzione d’imposta, è necessario che il reddito imponibile (riga 10) sia inferiore a un limite massimo calcolato nelle righe 4-8;
  • righe 13-16: se soddisfa i requisiti, il contribuente ha diritto a una riduzione d’imposta 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

I file résultats.txt (stato civile, figli, stipendio, imposta, maggiorazione, 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 conformi a quelli ottenuti con il simulatore dell’amministrazione fiscale.

4.3.3. Conclusione

L’algoritmo di calcolo dell’imposta, anche in casi ritenuti semplici, è complesso. Non torneremo più su questo argomento. Nel corso delle versioni, il suo nucleo rimarrà lo stesso nonostante alcune modifiche nella presentazione. Ci limiteremo quindi a commentare solo queste ultime.

4.4. Versione 2

4.4.1. Le modifiche

Nella versione precedente, i dati necessari al calcolo dell’imposta erano codificati in modo statico sotto forma di costanti e tabelle. Questo metodo è da evitare. Nella nuova versione, tali 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

// rigoroso rispetto dei tipi dichiarati dei parametri delle funzioni
declare (strict_types=1);

// definizione delle costanti
$TAXPAYERSDATA = "taxpayersdata.txt";
$RESULTATS = "resultats.txt";
$TAXADMINDATA = "taxadmindata.json";

// si recupera il contenuto del file dei dati fiscali
$fileContents = \file_get_contents($TAXADMINDATA);
$erreur = FALSE;
// errore?
if (!$fileContents) {
  // si registra l'errore
  $erreur = TRUE;
  $message = "Le fichier des données [$TAXADMINDATA] n'existe pas";
}

if (!$erreur) {
  // si recupera il codice jSON dal file di configurazione in un array associativo
  $taxAdminData = \json_decode($fileContents, true);
  // errore?
  if (!$taxAdminData) {
    // si registra l'errore
    $erreur = TRUE;
    $message = "Le fichier de données jSON [$TAXADMINDATA] n'a pu être exploité correctement";
  }
}

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

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

// apertura del file dei dati dei contribuenti
$taxpayersdata = fopen($TAXPAYERSDATA, "r");
if (!$taxpayersdata) {
  print "Impossible d'ouvrir le fichier des contribuables [$TAXPAYERSDATA]\n";
  // uscita
  exit;
}

// si elabora la riga corrente del file dei dati
while ($ligne = fgets($taxpayersdata, 100)) {
  // si rimuove l'eventuale carattere di fine riga
  $ligne = cutNewLineChar($ligne);
  // si recuperano i 3 campi coniuge:figli:stipendio che formano $ligne
  list($marié, $enfants, $salaire) = explode(",", $ligne);
  // si calcola l'imposta
  $result = calculImpot($taxAdminData, $marié, (int) $enfants, (int) $salaire);
  // si inserisce il risultato nel file dei risultati
  $result = ["marié" => $marié, "enfants" => $enfants, "salaire" => $salaire] + $result;
  fputs($résultats, \json_encode($result, JSON_UNESCAPED_UNICODE) . "\n");
  // dato successivo
}
// si chiudono i file
fclose($taxpayersdata);
fclose($résultats);

// fine
exit;

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

  // fine
  return($ligne);
}

// calcolo dell'imposta
// --------------------------------------------------------------------------
function calculImpot(array $taxAdminData, string $marié, int $enfants, float $salaire) {
  // $marié: sì, no
  // $enfants: numero di figli
  // $salaire: stipendio annuo
  // $taxAdminData: dati dell'amministrazione fiscale
  //
  // calcolo dell’imposta con figli
  $result1 = calculImpot2($taxAdminData, $marié, $enfants, $salaire);
  $impot1 = $result1["impôt"];
  // calcolo dell’imposta senza figli
  if ($enfants != 0) {
    $result2 = calculImpot2($taxAdminData, $marié, 0, $salaire);
    $impot2 = $result2["impôt"];
    // applicazione del limite massimo del quoziente familiare
    if ($enfants < 3) {
      // $PLAFOND_QF_DEMI_PART euro per i primi 2 figli
      $impot2 = $impot2 - $enfants * $taxAdminData["PLAFOND_QF_DEMI_PART"];
    } else {
      // $PLAFOND_QF_DEMI_PART euro per i primi 2 figli, il doppio per i successivi
      $impot2 = $impot2 - 2 * $taxAdminData["PLAFOND_QF_DEMI_PART"] - ($enfants - 2) * 2 * $taxAdminData["PLAFOND_QF_DEMI_PART"];
    }
  } else {
    $impot2 = $impot1;
    $result2 = $result1;
  }
  // si considera l’imposta più elevata con l’aliquota e la maggiorazione corrispondenti
  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"];
  }
  // calcolo di un’eventuale riduzione
  $décôte = getDecote($taxAdminData, $marié, $salaire, $impot);
  $impot -= $décôte;
  // calcolo di un’eventuale riduzione delle imposte
  $réduction = getRéduction($taxAdminData, $marié, $salaire, $enfants, $impot);
  $impot -= $réduction;
  // risultato
  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é: sì, no

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

// revenuImposable=stipendioAnnuale-detrazione
// la detrazione ha un valore minimo e uno massimo
function getRevenuImposable(array $taxAdminData, float $salaire): float {

  // risultato
  return floor($revenuImposable);
}

// calcola un'eventuale riduzione
function getDecote(array $taxAdminData, string $marié, float $salaire, float $impots): float {

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

// calcola un'eventuale riduzione
function getRéduction(array $taxAdminData, string $marié, float $salaire, int $enfants, float $impots): float {

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

Commenti

  • righe 11-19: si tenta di leggere il contenuto del file jSON denominato [TAXADMINDATA];
  • righe 21-30: se si è riusciti a leggere il file jSON, il suo contenuto viene decodificato nell'array associativo [$taxAdminData];
  • righe 32-36: se si è verificato un errore in una delle due operazioni precedenti, si scrive un messaggio di errore sulla console e il programma si interrompe;
  • la differenza rispetto alla versione 01 è che qui i dati (tabelle e costanti) dell’amministrazione fiscale si trovano nel tabellone associativo [$taxAdminData], mentre nella versione 01 erano contenuti in tabelle e costanti globali. È proprio la globalità di queste costanti a fare la differenza tra 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, è necessario passare la tabella associativa [$taxAdminData] come parametro a tutte le funzioni (righe 83, 129, 138, 145, 152);
  • ogni funzione della versione 02 deve utilizzare il contenuto della tabella [$taxAdminData];
  • righe 83-126: nella funzione [calculerImpot], dove prima si utilizzavano costanti globali o le tabelle [limites, coeffR, coeffN], ora si utilizza il contenuto della tabella [$taxAdminData] ricevuta come parametro (righe 99, 102);
  • tutte le altre funzioni sono state 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 dell’imposta sarà probabilmente lo stesso del 2019. Cambieranno solo le fasce di imposta e le costanti di calcolo. Basterà quindi aggiornare il file [taxadmindata.json]. Con la versione 01, è necessario accedere al 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.