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

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

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

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

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

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):
Il file results.txt (stato civile, figli, stipendio, imposta, sovrattassa, sconto, riduzione, aliquota fiscale) dei risultati ottenuti:
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):
Il file results.txt (stato civile, figli, stipendio, imposta, sovrattassa, sconto, riduzione, aliquota fiscale) dei risultati ottenuti:
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:

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.