Skip to content

11. Практичне завдання: версія 3

Image

Ця нова версія містить дві зміни:

  • дані, необхідні для розрахунку податку та надані податковою адміністрацією, розміщуються у файлі 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
}
  • результати розрахунку податку також будуть розміщені у файлі 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. Скрипт конфігурації [config.py]

Скрипт конфігурації матиме такий вигляд:


def configure():
    import os

    # абсолютний шлях до папки цього скрипта
    script_dir = os.path.dirname(os.path.abspath(__file__))
    # залежності програми
    absolute_dependencies = [
        f"{script_dir}/../shared",
    ]
    # конфігурація програми
    config = {
        # абсолютний шлях до файлу платників податків
        "taxpayersFilename"f"{script_dir}/../data/taxpayersdata.txt",
        # абсолютний шлях до файлу результатів
        "resultsFilename"f"{script_dir}/../data/résultats.json",
        # абсолютний шлях до файлу даних податкової адміністрації
        "admindataFilename"f"{script_dir}/../data/admindata.json"
    }
    # оновлення syspath
    from myutils import set_syspath

    set_syspath(absolute_dependencies)

    # застосовуємо конфігурацію
    return config
  • рядок 8: додаємо папку [shared] до Python Path. Ця папка містить модуль [impôts_module_02], який використовується головним скриптом;

11.2. Головний скрипт [main.py]

Головний скрипт версії 3 має такий вигляд:


# налаштовуємо додаток
import config

config = config.configure()

# syspath налаштовано — можна виконувати імпорт
from impôts_module_02 import calcul_impôt, get_admindata, get_taxpayers_data, record_results_in_json_file

# файл платників податків
taxpayers_filename = config['taxpayersFilename']
# файл результатів
results_filename = config['resultsFilename']
# файл даних податкової адміністрації
admindata_filename = config['admindataFilename']
# код
try:

    # зчитування даних податкової адміністрації
    admindata = get_admindata(admindata_filename)
    # читання даних платників податків
    taxpayers = get_taxpayers_data(taxpayers_filename)
    # список результатів
    results = []
    # розрахунок податку платників податків
    for taxpayer in taxpayers:
        # розрахунок податку повертає словник ключів
        # ['marié', 'enfants', 'salaire', 'impôt', 'surcôte', 'décôte', 'réduction', 'taux']
        result = calcul_impôt(admindata, taxpayer['marié'], taxpayer['enfants'], taxpayer['salaire'])
        # словник додано до списку результатів
        results.append(result)
    # результати зберігаються
    record_results_in_json_file(results_filename, results)
except BaseException as erreur:
    # можуть виникнути різні помилки: відсутність файлу, неправильний вміст файлу
    # виводиться повідомлення про помилку та закривається програма
    print(f"L'erreur suivante s'est produite : {erreur}]\n")
finally:
    print("Travail terminé...")

Примітки

  • у рядках 2–4 налаштовується програма, зокрема її Python Path;
  • рядок 7: імпортуються необхідні функції з [main.py];
  • рядки 9–14: імена файлів, які використовує додаток, отримуються з конфігурації;
  • головний скрипт версії 3 має три відмінності від скрипту версій 1 і 2:
  • рядок 21: дані податкової адміністрації беруться з файлу jSON [./data/admindata.json];
  • рядок 32: результати розрахунку податку записуються у файл jSON [./data/résultats.json];
  • рядок 7: функції версії 3 містяться в модулі [impots.modules.impôts_module_02];

11.3. Модуль [impots.v02.modules.impôts_module_02]

Модуль [impots.v02.modules.impôts_module_02] має таку структуру:

Image

  • у цьому модулі містяться функції, які вже були присутні в модулі, що використовувався у версії 1, однак із однією відмінністю. Коли модуль версії 2 використовує функцію, присутню в модулі версії 1, він робить це з додатковим параметром: [adminData] (рядки 29, 51, 77, 127). Цей параметр представляє словник податкових даних із файлів jSON та [adminData.json]. У модулі версії 1 ці дані не потрібно було передавати до функцій, оскільки вони були глобально визначені для них, завдяки чому функції їх знали;

11.4. Зчитування даних податкової адміністрації

Функція [get_admindata] має такий вигляд:


# зчитування даних податкової служби у файл jSON
# ----------------------------------------
def get_admindata(admindata_filename: str) -> dict:
    # читання даних податкової служби
    # дозволяється вивести можливі винятки: відсутність файлу, некоректний вміст jSON
    file = None
    try:
        # відкриття файлу jSON у режимі читання
        file = codecs.open(admindata_filename, "r", "utf8")
        # перенесення вмісту до словника
        admin_data = json.load(file)
        # повертається результат
        return admin_data
    finally:
        # закриття файлу, якщо він був відкритий
        if file:
            file.close()
  • рядок 9: отримуємо словник зображень із прочитаного файлу jSON;

11.5. Збереження результатів

Функція [record_results_in_json_file] працює наступним чином:


# запис результатів у файл jSON
# ----------------------------------------
def record_results_in_json_file(results_filename: str, results: list):
    file = None
    try:
        # відкриття файлу результатів
        file = codecs.open(results_filename, "w", "utf8")
        # запис блоком
        json.dump(results, file, ensure_ascii=False)
    finally:
        # закриття файлу, якщо він був відкритий
        if file:
            file.close()
  • рядок 7: створюється файл, закодований у форматі UTF-8;
  • рядок 9: записується список [results] у файл jSON. Символи UTF-8 не піддаються екрануванню (ensure_ascii=False);

11.6. Зміни у функціях

Деякі функції тепер приймають додатковий параметр [admin_data]. Це дещо змінює їхній вигляд. Візьмемо, наприклад, функцію [calcul_impôt]:


# розрахунок податку — крок 1
# ----------------------------------------
def calcul_impôt(admin_data: dict, marié: str, enfants: int, salaire: int) -> dict:
    # одружений: так, ні
    # діти: кількість дітей
    # зарплата: річна зарплата
    # ліміти, коефіцієнт, коефіцієнт: таблиці даних, що дозволяють розрахувати податок
    #
    # розрахунок податку з урахуванням дітей
    result1 = calcul_impôt_2(admin_data, marié, enfants, salaire)
    impot1 = result1["impôt"]
    # розрахунок податку без урахування дітей
    if enfants != 0:
        result2 = calcul_impôt_2(admin_data, marié, 0, salaire)
        impot2 = result2["impôt"]
        # застосування обмеження сімейного коефіцієнта
        if enfants < 3:
            # PLAFOND_QF_DEMI_PART євро для перших двох дітей
            impot2 = impot2 - enfants * admin_data['plafond_qf_demi_part']
        else:
            # PLAFOND_QF_DEMI_PART євро для перших двох дітей, удвічі більше для наступних
            impot2 = impot2 - 2 * admin_data['plafond_qf_demi_part'] - (enfants - 2) * 2 * admin_data[
                'plafond_qf_demi_part']
    else:
        impot2 = impot1
        result2 = result1

    # беремо найвищий податок із відповідною ставкою та надбавкою
    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"]

    # розрахунок можливого зниження
    décôte = get_décôte(admin_data, marié, salaire, impot)
    impot -= décôte
    # розрахунок можливого зменшення податку
    réduction = get_réduction(admin_data, marié, salaire, enfants, impot)
    impot -= réduction
    # результат
    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}

Примітки

  • там, де [calcul_impôt] викликає інші функції, вона передає [admin_data] як перший параметр (рядки 10, 14, 39, 42);
  • там, де [calcul_impôt] використовує податкові константи, вона тепер звертається до словника [admin_data] (рядки 19, 22);

Усі функції, що приймають [admin_data] як параметр, зазнають таких самих змін.

11.7. Результати

Отримані результати наведені на початку розділу 8.3.