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 [results.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

    #  absolute path of this script's folder
    script_dir = os.path.dirname(os.path.abspath(__file__))
    #  application dependencies
    absolute_dependencies = [
        f"{script_dir}/../shared",
    ]
    #  application configuration
    config = {
        #  absolute path of the taxpayer file
        "taxpayersFilename": f"{script_dir}/../data/taxpayersdata.txt",
        #  absolute path of the results file
        "resultsFilename": f"{script_dir}/../data/résultats.json",
        #  absolute path of tax administration data file
        "admindataFilename": f"{script_dir}/../data/admindata.json"
    }
    #  update syspath
    from myutils import set_syspath

    set_syspath(absolute_dependencies)

    #  return the config
    return config
  • السطر 8: أضف المجلد [shared] إلى مسار Python. يحتوي هذا المجلد على الوحدة النمطية [impôts_module_02] التي يستخدمها البرنامج النصي الرئيسي؛

11.2. البرنامج النصي الرئيسي [main.py]

النص البرمجي الرئيسي للإصدار 3 هو كما يلي:

#  configure the application
import config

config = config.configure()

#  syspath is configured - imports can be made
from impôts_module_02 import calcul_impôt, get_admindata, get_taxpayers_data, record_results_in_json_file

#  taxpayer file
taxpayers_filename = config['taxpayersFilename']
#  results file
results_filename = config['resultsFilename']
#  tax administration data file
admindata_filename = config['admindataFilename']
#  code
try:

    #  reading tax administration data
    admindata = get_admindata(admindata_filename)
    #  reading taxpayer data
    taxpayers = get_taxpayers_data(taxpayers_filename)
    #  results list
    results = []
    #  taxpayers' taxes are calculated
    for taxpayer in taxpayers:
        #  tax calculation returns a dictionary of keys
        #  ['married', 'children', 'salary', 'tax', 'surcôte', 'décôte', 'réduction', 'taux']
        result = calcul_impôt(admindata, taxpayer['marié'], taxpayer['enfants'], taxpayer['salaire'])
        #  the dictionary is added to the list of results
        results.append(result)
    #  we record the results
    record_results_in_json_file(results_filename, results)
except BaseException as erreur:
    #  there may be various errors: no file, incorrect file content
    #  display the error and exit the application
    print(f"L'erreur suivante s'est produite : {erreur}]\n")
finally:
    print("Travail terminé...")

ملاحظات

  • الأسطر 2–4: نقوم بتكوين التطبيق، وتحديدًا مسار Python الخاص به؛
  • السطر 7: نستورد الوظائف التي نحتاجها إلى [main.py]؛
  • الأسطر 9–14: يتم استرداد أسماء الملفات التي يستخدمها التطبيق من التكوين؛
  • يحتوي البرنامج النصي الرئيسي في الإصدار 3 على ثلاثة اختلافات مقارنة بالإصدارين 1 و 2:
  • السطر 21: يتم استرداد بيانات سلطة الضرائب من ملف JSON [./data/admindata.json]؛
  • السطر 32: يتم وضع نتائج حساب الضرائب في ملف JSON [./data/results.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] هي كما يلي:

#  read data from tax authorities in a jSON file
# ----------------------------------------
def get_admindata(admindata_filename: str) -> dict:
    #  reading tax administration data
    #  we let any exceptions go up: file missing, jSON content incorrect
    file = None
    try:
        #  open file jSON in read mode
        file = codecs.open(admindata_filename, "r", "utf8")
        #  transfer content to a dictionary
        admin_data = json.load(file)
        #  we return the result
        return admin_data
    finally:
        #  close the file if it has been opened
        if file:
            file.close()
  • السطر 9: استرجاع قاموس الصور من ملف JSON الذي تمت قراءته؛

11.5. حفظ النتائج

وظيفة [record_results_in_json_file] هي كما يلي:

#  writing results to a jSON file
# ----------------------------------------
def record_results_in_json_file(results_filename: str, results: list):
    file = None
    try:
        #  opening the results file
        file = codecs.open(results_filename, "w", "utf8")
        #  block writing
        json.dump(results, file, ensure_ascii=False)
    finally:
        #  close the file if it has been opened
        if file:
            file.close()
  • السطر 7: إنشاء ملف مشفر بـ UTF-8؛
  • السطر 9: كتابة قائمة [results] إلى ملف JSON. لا يتم تجاوز أحرف UTF-8 (ensure_ascii=False

11.6. تعديلات الوظائف

تتلقى بعض الوظائف الآن معلمة [admin_data] إضافية. وهذا يغير صيغتها قليلاً. خذ على سبيل المثال وظيفة [calcul_impôt]:

#  tax calculation - step 1
# ----------------------------------------
def calcul_impôt(admin_data: dict, marié: str, enfants: int, salaire: int) -> dict:
    #  married: yes, no
    #  children: number of children
    #  salary: annual salary
    #  limits, coeffr, coeffn: data tables for tax calculation
    #
    #  tax calculation with children
    result1 = calcul_impôt_2(admin_data, marié, enfants, salaire)
    impot1 = result1["impôt"]
    #  tax calculation without children
    if enfants != 0:
        result2 = calcul_impôt_2(admin_data, 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 * admin_data['plafond_qf_demi_part']
        else:
            #  PLAFOND_QF_DEMI_PART euros for the first 2 children, double for subsequent children
            impot2 = impot2 - 2 * admin_data['plafond_qf_demi_part'] - (enfants - 2) * 2 * admin_data[
                '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 = get_décôte(admin_data, marié, salaire, impot)
    impot -= décôte
    #  calculation of any tax reduction
    réduction = get_réduction(admin_data, marié, salaire, enfants, impot)
    impot -= réduction
    #  result
    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_tax] دوال أخرى، فإنها تمرر [admin_data] كمعلمة أولى (الأسطر 10 و14 و39 و42)؛
  • عندما تستخدم [tax_calculation] ثوابت الضرائب، فإنها تصل إليها الآن عبر قاموس [admin_data] (الأسطر 19، 22)؛

تخضع جميع الدوال التي تتلقى [admin_data] كمعلمة لنفس هذه الأنواع من التغييرات.

11.7. النتائج

النتائج التي تم الحصول عليها هي تلك المعروضة في بداية القسم 8.3.