Skip to content

11. Esercizio pratico: versione 3

Image

Questa nuova versione introduce due modifiche:

  • i dati necessari al calcolo dell'imposta e forniti dall'amministrazione fiscale sono inseriti in un file jSON [admindata.json]:

{
    "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
}
  • anche i risultati del calcolo dell’imposta saranno inseriti in un file jSON [résultats.json]:

[
  {
    "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": 200000,
    "impôt": 42842,
    "surcôte": 17283,
    "décôte": 0,
    "réduction": 0,
    "taux": 0.41
  }
]

11.1. Lo script di configurazione [config.py]

Lo script di configurazione sarà il seguente:


def configure():
    import os

    # percorso assoluto della cartella contenente questo script
    script_dir = os.path.dirname(os.path.abspath(__file__))
    # dipendenze dell'applicazione
    absolute_dependencies = [
        f"{script_dir}/../shared",
    ]
    # configurazione dell'applicazione
    config = {
        # percorso assoluto del file dei contribuenti
        "taxpayersFilename"f"{script_dir}/../data/taxpayersdata.txt",
        # percorso assoluto del file dei risultati
        "resultsFilename"f"{script_dir}/../data/résultats.json",
        # percorso assoluto del file dei dati dell'amministrazione fiscale
        "admindataFilename"f"{script_dir}/../data/admindata.json"
    }
    # aggiornamento del syspath
    from myutils import set_syspath

    set_syspath(absolute_dependencies)

    # si ripristina la configurazione
    return config
  • riga 8: si aggiunge la cartella [shared] al Python Path. Questa cartella contiene il modulo [impôts_module_02] utilizzato dallo script principale;

11.2. Script principale [main.py]

Lo script principale della versione 3 è il seguente:


# si configura l'applicazione
import config

config = config.configure()

# il syspath è configurato - è possibile eseguire le importazioni
from impôts_module_02 import calcul_impôt, get_admindata, get_taxpayers_data, record_results_in_json_file

# file dei contribuenti
taxpayers_filename = config['taxpayersFilename']
# file dei risultati
results_filename = config['resultsFilename']
# file dei dati dell'amministrazione fiscale
admindata_filename = config['admindataFilename']
# codice
try:

    # lettura dei dati dell'amministrazione fiscale
    admindata = get_admindata(admindata_filename)
    # lettura dei dati dei contribuenti
    taxpayers = get_taxpayers_data(taxpayers_filename)
    # elenco dei risultati
    results = []
    # calcolo dell'imposta dei contribuenti
    for taxpayer in taxpayers:
        # il calcolo dell'imposta restituisce un dizionario di chiavi
        # ['marié', 'enfants', 'salaire', 'impôt', 'surcôte', 'décôte', 'réduction', 'taux']
        result = calcul_impôt(admindata, taxpayer['marié'], taxpayer['enfants'], taxpayer['salaire'])
        # il dizionario viene aggiunto all'elenco dei risultati
        results.append(result)
    # i risultati vengono salvati
    record_results_in_json_file(results_filename, results)
except BaseException as erreur:
    # possono verificarsi diversi errori: file mancante, contenuto del file errato
    # viene visualizzato l'errore e si esce dall'applicazione
    print(f"L'erreur suivante s'est produite : {erreur}]\n")
finally:
    print("Travail terminé...")

Note

  • righe 2-4: si configura l’applicazione, in particolare il suo Python Path;
  • riga 7: si importano le funzioni necessarie in [main.py];
  • righe 9-14: i nomi dei file utilizzati dall'applicazione vengono recuperati dalla configurazione;
  • lo script principale della versione 3 presenta tre differenze rispetto a quello delle versioni 1 e 2:
  • riga 21: i dati dell'amministrazione fiscale sono ricavati dal file jSON [./data/admindata.json];
  • riga 32: i risultati del calcolo dell'imposta vengono inseriti nel file jSON [./data/résultats.json];
  • riga 7: le funzioni della versione 3 si trovano nel modulo [impots.modules.impôts_module_02];

11.3. Il modulo [impots.v02.modules.impôts_module_02]

Il modulo [impots.v02.modules.impôts_module_02] presenta la seguente struttura:

Image

  • nel modulo si ritrovano funzioni già presenti nel modulo utilizzato dalla versione 1, con una differenza tuttavia. Quando il modulo della versione 2 riprende una funzione presente nel modulo della versione 1, lo fa con un parametro aggiuntivo: [adminData] (righe 29, 51, 77, 127). Questo parametro rappresenta il dizionario dei dati fiscali provenienti dal file jSON [adminData.json]. Nel modulo della versione 1, questi dati non dovevano essere passati alle funzioni poiché erano definiti globalmente a livello di queste ultime, il che faceva sì che le funzioni ne fossero a conoscenza;

11.4. Lettura dei dati dell’amministrazione fiscale

La funzione [get_admindata] è la seguente:


# lettura dei dati dell'amministrazione fiscale in un file jSON
# ----------------------------------------
def get_admindata(admindata_filename: str) -> dict:
    # lettura dei dati dell'amministrazione fiscale
    # si lasciano risalire eventuali eccezioni: file mancante, contenuto jSON non corretto
    file = None
    try:
        # apertura del file jSON in modalità di lettura
        file = codecs.open(admindata_filename, "r", "utf8")
        # trasferimento del contenuto in un dizionario
        admin_data = json.load(file)
        # restituzione del risultato
        return admin_data
    finally:
        # chiusura del file se è stato aperto
        if file:
            file.close()
  • riga 9: si recupera il dizionario delle immagini dal file jSON letto;

11.5. Salvataggio dei risultati

La funzione [record_results_in_json_file] è la seguente:


# scrittura dei risultati in un file jSON
# ----------------------------------------
def record_results_in_json_file(results_filename: str, results: list):
    file = None
    try:
        # apertura del file dei risultati
        file = codecs.open(results_filename, "w", "utf8")
        # scrittura in blocco
        json.dump(results, file, ensure_ascii=False)
    finally:
        # chiusura del file se è stato aperto
        if file:
            file.close()
  • riga 7: si crea un file codificato in UTF-8;
  • riga 9: si scrive l'elenco [results] nel file jSON. I caratteri UTF-8 non vengono sottoposti a escape (ensure_ascii=False);

11.6. Modifica delle funzioni

Alcune funzioni ora ricevono un parametro aggiuntivo [admin_data]. Ciò modifica leggermente la loro sintassi. Prendiamo ad esempio la funzione [calcul_impôt]:


# calcolo dell'imposta - fase 1
# ----------------------------------------
def calcul_impôt(admin_data: dict, marié: str, enfants: int, salaire: int) -> dict:
    # stato civile: sì, no
    # figli: numero di figli
    # stipendio: stipendio annuo
    # limiti, coeffr, coeffn: le tabelle dei dati che consentono il calcolo dell'imposta
    #
    # calcolo dell’imposta con figli
    result1 = calcul_impôt_2(admin_data, marié, enfants, salaire)
    impot1 = result1["impôt"]
    # calcolo dell'imposta senza figli
    if enfants != 0:
        result2 = calcul_impôt_2(admin_data, marié, 0, salaire)
        impot2 = result2["impôt"]
        # applicazione del limite massimo al quoziente familiare
        if enfants < 3:
            # PLAFOND_QF_DEMI_PART euro per i primi 2 figli
            impot2 = impot2 - enfants * admin_data['plafond_qf_demi_part']
        else:
            # PLAFOND_QF_DEMI_PART euro per i primi 2 figli, il doppio per i successivi
            impot2 = impot2 - 2 * admin_data['plafond_qf_demi_part'] - (enfants - 2) * 2 * admin_data[
                '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 = get_décôte(admin_data, marié, salaire, impot)
    impot -= décôte
    # calcolo di un’eventuale riduzione delle imposte
    réduction = get_réduction(admin_data, marié, salaire, enfants, impot)
    impot -= réduction
    # risultato
    return {"marié": marié, "enfants": enfants, "salaire": salaire, "impôt": math.floor(impot), "surcôte": surcôte,
            "décôte": décôte, "réduction": réduction, "taux": taux}

Note

  • laddove [calcul_impôt] chiama altre funzioni, passa [admin_data] come primo parametro (righe 10, 14, 39, 42);
  • laddove [calcul_impôt] utilizza costanti fiscali, ora passa attraverso il dizionario [admin_data] (righe 19, 22);

Tutte le funzioni che ricevono [admin_data] come parametro subiscono lo stesso tipo di modifiche.

11.7. Risultati

I risultati ottenuti sono quelli presentati all’inizio del paragrafo 8.3.