11. تمرین عملی: نسخه ۳

این نسخه جدید دو تغییر را معرفی میکند:
- دادههای مورد نیاز برای محاسبه مالیات، که توسط مقامات مالیاتی ارائه شده است، در فایلی به نام 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
- خط ۸: پوشه [shared] را به مسیر پایتون (Python Path) اضافه کنید. این پوشه شامل ماژول [impôts_module_02] است که توسط اسکریپت اصلی استفاده میشود؛
11.2. اسکریپت اصلی [main.py]
اسکریپت اصلی برای نسخه ۳ به شرح زیر است:
#پیکربندی برنامه
import config
config = config.configure()
#مسیر سیستم پیکربندی شده است – اکنون میتوان واردات را انجام داد
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é...")
یادداشتها
- خطوط ۲–۴: برنامه پیکربندی میشود، بهویژه مسیر پایتون (Python Path) آن؛
- خط ۷: توابع مورد نیاز از [main.py] وارد میشوند؛
- خطوط ۹–۱۴: نام فایلهای مورد استفاده توسط برنامه از پیکربندی بازیابی میشوند؛
- اسکریپت اصلی در نسخه ۳ از نسخههای ۱ و ۲ در سه مورد تفاوت دارد:
- خط ۲۱: دادههای مرجع مالیاتی از فایل jSON [./data/admindata.json] گرفته میشود؛
- خط ۳۲: نتایج محاسبه مالیات در فایل jSON [./data/résultats.json] ذخیره میشوند؛
- خط ۷: توابع مربوط به نسخه ۳ در ماژول [impots.modules.impôts_module_02] قرار دارند؛
11.3. ماژول [impots.v02.modules.impôts_module_02]
ماژول [impots.v02.modules.impôts_module_02] ساختار زیر را دارد:

- این ماژول حاوی توابعی است که پیش از این در ماژول مورد استفاده نسخه ۱ وجود داشتند، با این تفاوت که وقتی ماژول نسخه ۲ از توابعی که در ماژول نسخه ۱ موجود هستند استفاده مجدد میکند، این کار را با یک پارامتر اضافی انجام میدهد: [adminData] (خطوط ۲۹، ۵۱، ۷۷، ۱۲۷). این پارامتر نمایانگر فرهنگ لغت دادههای مالیاتی از فایل jSON [adminData.json] است. در ماژول نسخه ۱، نیازی نبود که این دادهها به توابع ارسال شوند زیرا به صورت سراسری برای آنها تعریف شده بود، به این معنی که توابع از قبل از آن آگاه بودند؛
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()
- خط ۹: فرهنگ لغت تصویر از فایل 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()
- خط ۷: فایلی با کدگذاری UTF-8 ایجاد میشود؛
- خط ۹: لیست [results] در فایل jSON نوشته میشود. کاراکترهای UTF-8 فرارسازی نشدهاند (ensure_ascii=False);
11.6. تغییرات در توابع
برخی از توابع اکنون یک پارامتر اضافی به نام [admin_data] میگیرند. این موضوع سینتکس آنها را اندکی تغییر میدهد. برای مثال، تابع [calcul_impôt] را در نظر بگیرید:
#محاسبه مالیات – مرحله ۱
# ----------------------------------------
def calcul_impôt(admin_data: dict, marié: str, enfants: int, salaire: int) -> dict:
# متأهل: بله، خیر
# فرزندان: تعداد فرزندان
# حقوق: حقوق سالانه
#آستانهها، coeffr، coeffn: جداول دادهای مورد استفاده برای محاسبه مالیات
#
# محاسبه مالیات شامل فرزندان
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] را به عنوان پارامتر اول ارسال میکند (خطوط ۱۰، ۱۴، ۳۹، ۴۲)؛
- جایی که [calcul_impôt] از ثابتهای مالیاتی استفاده میکند، اکنون از طریق فرهنگ لغت [admin_data] به آنها دسترسی پیدا میکند (خطوط ۱۹، ۲۲)؛
تمام توابعی که [admin_data] را بهعنوان پارامتر میگیرند، دچار همین نوع تغییرات میشوند.
11.7. نتایج
نتایج بهدستآمده همان نتایجی هستند که در ابتدای بخش 8.3 ارائه شدهاند.