4. Esercizio pratico – versioni 1 e 2
4.1. Il problema

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]:

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:
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:
il che dà l’imposta lorda I=0,45*R – 20163,45*nbParts.
4.1.2. Limite massimo del quoziente familiare

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:
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

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

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

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):
I file résultats.txt (stato civile, figli, stipendio, imposta, maggiorazione, riduzione, aliquota fiscale) dei risultati ottenuti:
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):
I file résultats.txt (stato civile, figli, stipendio, imposta, maggiorazione, riduzione, aliquota fiscale) dei risultati ottenuti:
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:

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.