Skip to content

8. تمرین عملی – نسخه ۱

8.1. مسئله

Image

جدول بالا برای محاسبه مالیات در حالت ساده‌شده یک مؤدی که تنها حقوق خود را برای اظهار دارد، استفاده می‌شود. همان‌طور که در یادداشت (۱) اشاره شده است، مالیات محاسبه‌شده به این روش، مالیات قبل از اعمال سه مکانیزم است:

  • محدود کردن ضریب خانوادگی، که برای افراد با درآمد بالا اعمال می‌شود؛
  • بازپرداخت مالیات و کاهش مالیات که برای درآمدهای پایین اعمال می‌شوند؛

بنابراین محاسبه مالیات شامل مراحل زیر است [http://impotsurlerevenu.org/comprendre-le-calcul-de-l-impot/1217-calcul-de-l-impot-2019.php]:

Image

ما پیشنهاد می‌کنیم برنامه‌ای برای محاسبه بدهی مالیاتی مودی در حالت ساده‌شده‌ای که تنها حقوق خود را برای اظهار دارد، بنویسیم:

8.1.1. محاسبه مالیات ناخالص

مالیات ناخالص را می‌توان به صورت زیر محاسبه کرد:

ابتدا، تعداد سهام مودی را محاسبه می‌کنیم:

  • هر والد یک سهم مشارکت می‌کند؛
  • دو فرزند اول هر کدام نیم سهم می‌پردازند؛
  • فرزندان بعدی هر کدام یک سهم مشارکت می‌کنند:

بنابراین تعداد سهام به این صورت است:

  • nbParts = 1 + nbEnfants * 0.5 + (nbChildren - 2) * 0.5 اگر کارمند متأهل نباشد؛
  • nbParts = 2 + nbChildren * 0.5 + (nbChildren - 2) * 0.5 اگر متأهل باشند؛
    • که در آن nbEnfants تعداد فرزندان است؛
  • درآمد مشمول مالیات R به صورت R = 0.9 * S محاسبه می‌شود، که در آن S حقوق سالانه است؛
  • ضریب خانوادگی به صورت QF = R / nbParts محاسبه می‌شود؛
  • مالیات ناخالص I بر اساس داده‌های زیر (۲۰۱۹) محاسبه می‌شود:
۹۹۶۴
0
0
۲۷٬۵۱۹
0.14
۱٬۳۹۴٫۹۶
۷۳٬۷۷۹
0.3
۵٬۷۹۸
۱۵۶٬۲۴۴
0.4
۱۳٬۹۱۳٫۶۹
0
0.45
20163.45

هر سطر دارای ۳ فیلد است: champ1، champ2، champ3. برای محاسبه مالیات I، اولین ردیفی را که در آن QFfield1 باشد پیدا کرده و مقادیر آن ردیف را برمی‌داریم. برای مثال، برای کارمندی که متأهل با دو فرزند است و حقوق سالانه‌اش S برابر با ۵۰٬۰۰۰ یورو است:

درآمد مشمول مالیات: R = 0.9 × S = 45,000

تعداد پله های مالیاتی: nbParts = 2 + 2 * 0.5 = 3

ضریب خانوادگی: QF = ۴۵٬۰۰۰ / ۳ = ۱۵٬۰۰۰

اولین خطی که QF <= field1 است به شرح زیر است:

    27519    0.14    1394.96

بنابراین مالیات I برابر است با 0.14*R – 1394.96*nbParts=[0,14*45000-1394,96*3]=2115. مالیات به نزدیک‌ترین یورو به سمت پایین گرد می‌شود.

اگر شرط QFfield1 از خط اول به بعد برقرار باشد، مالیات صفر است.

اگر QF به‌گونه‌ای باشد که شرط QF <= field1 هرگز برقرار نشود، ضرایب مربوط به آخرین خط استفاده می‌شوند. در این صورت:

    0    0.45    20163.45

که مالیات ناخالص I = 0.45*R – 20163.45*nbParts را می‌دهد.

8.1.2. سقف نسبت خانوادگی

Image

برای تعیین اینکه آیا سقف ضریب خانوادگی QF اعمال می‌شود، مالیات ناخالص بدون در نظر گرفتن فرزندان مجدداً محاسبه می‌شود. مجدداً، برای کارمند متأهل با دو فرزند و حقوق سالانه S برابر با ۵۰٬۰۰۰ یورو:

درآمد مشمول مالیات: R = 0.9 × S = 45,000

تعداد پله های مالیاتی: nbParts = 2 (فرزندان دیگر در نظر گرفته نمی‌شوند)

ضریب خانوادگی: QF = 45,000 / 2 = 22,500

اولین خطی که QF <= field1 است به شرح زیر است:

    27519    0.14    1394.96

بنابراین مالیات I برابر است با 0.14*R – 1394.96*nbParts = [0,14*45000-1394,96*2] = 3510.

حداکثر معافیت مربوط به فرزند: ۱۵۵۱ * ۲ = ۳۱۰۲ یورو

حداقل مالیات: ۳۵۱۰ – ۳۱۰۲ = ۴۰۸ یورو

مالیات ناخالص، که قبلاً به مبلغ ۲٬۱۱۵ یورو (بر اساس ۳ رده مالیاتی) محاسبه شده است، از حداقل مالیات ۴۰۸ یورو بیشتر است، بنابراین سقف خانوادگی در اینجا اعمال نمی‌شود.

به‌طور کلی، مالیات ناخالص از (مالیات۱، مالیات۲) بزرگ‌تر است، که در آن:

  • [impôt1]: مالیات ناخالص محاسبه شده با احتساب فرزندان است؛
  • [impôt2]: مالیات ناخالص محاسبه شده بدون احتساب فرزندان و کاهش‌یافته با حداکثر معافیت (در اینجا ۱٬۵۵۱ یورو به ازای هر نیم‌سهم) مربوط به فرزندان است؛

8.1.3. محاسبه تخفیف مالیاتی

Image

بار دیگر، برای کارمند متأهل با دو فرزند و حقوق سالانه S برابر با ۵۰,۰۰۰ یورو:

مالیات ناخالص (۲۱۱۵) از مرحله قبلی کمتر از ۲۶۲۷ یورو برای یک زوج متأهل (۱۵۹۵ یورو برای یک فرد مجرد) است: بنابراین معافیت مالیاتی اعمال می‌شود. این معافیت به شرح زیر محاسبه می‌شود:

تخفیف = آستانه (برای زوج = ۱٬۹۷۰ / برای فرد مجرد = ۱٬۱۹۶) – ۰٫۷۵ × مالیات ناخالص

تخفیف = ۱۹۷۰ – ۰.۷۵ × ۲۱۱۵ = ۳۸۳.۷۵، گرد شده به ۳۸۴ یورو.

مالیات ناخالص جدید = ۲۱۱۵ – ۳۸۴ = ۱۷۳۱ یورو

8.1.4. محاسبه کاهش مالیات

Image

زیر یک آستانه مشخص، کاهشی ۲۰ درصدی بر مالیات ناخالص حاصل از محاسبات قبلی اعمال می‌شود. در سال ۲۰۱۹، آستانه‌ها به شرح زیر است:

  • فرد مجرد: ۲۱٬۰۳۷ یورو؛
  • زوج: ۴۲٬۰۷۴ یورو؛ (عدد ۳۷٬۹۶۸ که در مثال بالا استفاده شده به نظر نادرست است)؛

این آستانه با مقدار زیر افزایش می‌یابد: ۳۷۹۷ * (تعداد نیم‌سهام اهدایی توسط فرزندان).

بار دیگر، برای کارمند متأهل با دو فرزند و حقوق سالانه S برابر با ۵۰,۰۰۰ یورو:

  • درآمد مشمول مالیات او (۴۵٬۰۰۰ یورو) کمتر از آستانه (۴۲٬۰۷۴ + ۲ × ۳٬۷۹۷) = ۴۹٬۶۶۸ یورو است؛
  • بنابراین او مستحق ۲۰ درصد کاهش در مالیات خود است: ۱۷۳۱ × ۰.۲ = ۳۴۶.۲ یورو، که به ۳۴۷ یورو گرد شده است؛
  • مالیات ناخالص مودی به این صورت درمی‌آید: ۱,۷۳۱ – ۳۴۷ = ۱,۳۸۴ یورو؛

8.1.5. محاسبه مالیات خالص

محاسبه ما در اینجا به پایان می‌رسد: مالیات خالص قابل پرداخت ۱٬۳۸۴ یورو خواهد بود. در واقع، مؤدی ممکن است واجد شرایط دریافت کاهش‌های دیگری باشد، به‌ویژه برای اهدای کمک‌های مالی به سازمان‌های دارای منافع عمومی یا عمومی.

8.1.6. افراد با درآمد بالا

مثال قبلی ما برای اکثریت کارکنان صدق می‌کند. با این حال، محاسبه مالیات برای افراد با درآمد بالا متفاوت است.

8.1.6.1. سقف کاهش ۱۰ درصدی بر درآمد سالانه

در اکثر موارد، درآمد مشمول مالیات با استفاده از فرمول زیر محاسبه می‌شود: R = 0.9 × S، که در آن S حقوق سالانه است. این به عنوان کاهش ۱۰ درصدی شناخته می‌شود. این کاهش مشمول یک سقف است. در سال ۲۰۱۹:

  • نمی‌تواند از ۱۲٬۵۰۲ یورو تجاوز کند؛
  • نمی‌تواند کمتر از ۴۳۷ یورو باشد؛

بیایید مورد یک کارمند مجرد بدون فرزند با حقوق سالانه ۲۰۰,۰۰۰ یورو را در نظر بگیریم:

  • کاهش ۱۰ درصدی معادل ۲۰۰,۰۰۰ یورو > ۱۲,۵۰۲ یورو است. بنابراین، این کاهش به ۱۲,۵۰۲ یورو محدود می‌شود؛

8.1.6.2. سقف ضریب خانوادگی

فرض کنید موردی را در نظر بگیریم که سقف ضریب خانوادگی، همان‌طور که در بخش |سقف ضریب خانوادگی| توضیح داده شده است، اعمال می‌شود. فرض کنیم یک زوج با سه فرزند و درآمد سالانه ۱۰۰٬۰۰۰ یورو را در نظر بگیریم. بیایید دوباره مراحل محاسبه را مرور کنیم:

  • معافیت ۱۰ درصدی ۱۰,۰۰۰ یورو است که < ۱۲,۵۰۲ یورو است. بنابراین درآمد مشمول مالیات R برابر است با ۱۰۰,۰۰۰ – ۱۰,۰۰۰ = ۹۰,۰۰۰ یورو؛
  • این زوج دارای nbParts = 2 + 0.5 × 2 + 1 = 4 سهم هستند؛
  • بنابراین ضریب خانوادگی آنها QF = R / nbParts = 90,000 / 4 = 22,500 یورو است؛
  • مالیات ناخالص آنها I1 با فرزندان، I1 = 0.14 × 90,000 – 1,394.96 × 4 = 7,020 یورو است؛
  • مالیات ناخالص او I2 بدون فرزندان:
  • QF = ۹۰٬۰۰۰ / ۲ = ۴۵٬۰۰۰ یورو؛
  • I2 = 0.3 × 90,000 – 5,798 × 2 = 15,404 یورو؛
  • قانونی که ضریب خانوادگی را محدود می‌کند، بیان می‌دارد که مزایایی که از بابت فرزندان به دست می‌آید نمی‌تواند از (۱۵۵۱ × ۴ سهم نیم‌برادر) = ۶۲۰۴ یورو تجاوز کند. با این حال، در این مورد، مقدار I2-I1 برابر است با ۱۵۴۰۴ – ۷۰۲۰ = ۸۳۸۴ یورو، که بنابراین از ۶۲۰۴ یورو بیشتر است؛
  • بنابراین مالیات ناخالص مجدداً به صورت I3 = I2-6204 = 15,404 – 6,204 = 9,200 یورو محاسبه می‌شود؛

این زوج نه معافیت مالیاتی دریافت می‌کنند و نه کاهش مالیاتی، و صورتحساب مالیاتی نهایی آنها ۹۲۰۰ یورو خواهد بود.

8.1.7. اعداد رسمی

محاسبه مالیات پیچیده است. در سراسر این سند، محاسبات بر اساس مثال‌های زیر خواهد بود. نتایج از شبیه‌ساز سازمان مالیاتی گرفته شده است |https://www3.impots.gouv.fr/simulateur/calcul_impot/2019/simplifie/index.htm|:

مودی
نتایج رسمی
نتایج حاصل از الگوریتم در سند
زوجی با دو فرزند و درآمد سالانه ۵۵٬۵۵۵ یورو
مالیات = ۲٬۸۱۵ یورو
نرخ مالیات = ۱۴ درصد
مالیات = ۲٬۸۱۴ یورو
نرخ مالیات = ۱۴٪
زوجی با دو فرزند و درآمد سالانه ۵۰,۰۰۰ یورو
مالیات = ۱۳۸۵ یورو
کاهش مالیات = ۷۲۰ یورو
کاهش = ۰ یورو
نرخ مالیات = ۱۴٪
مالیات = ۱۳۸۴ یورو
تخفیف = ۳۸۴ یورو
معافیت مالیاتی = ۳۴۷ یورو
نرخ مالیات = ۱۴٪
زوجی با سه فرزند و درآمد سالانه ۵۰,۰۰۰ یورو
مالیات = ۰ یورو
تخفیف = ۳۸۴ یورو
کاهش = ۳۴۶ یورو
نرخ مالیات = ۱۴٪
مالیات = ۰ یورو
تخفیف = ۷۲۰ یورو
کاهش = ۰ یورو
نرخ مالیات = 14%
متأهل با دو فرزند و درآمد سالانه ۱۰۰,۰۰۰ یورو
مالیات = ۱۹٬۸۸۴ یورو
تخفیف = ۰ یورو
معافیت = ۰ یورو
نرخ مالیات = ۴۱٪
مالیات = ۱۹٬۸۸۴ یورو
سربار = ۴٬۴۸۰ یورو
تخفیف = ۰ یورو
کاهش = ۰ یورو
نرخ مالیات = ۴۱٪
مجرد با ۳ فرزند و درآمد سالانه ۱۰۰,۰۰۰ یورو
مالیات = ۱۶٬۷۸۲ یورو
تخفیف = ۰ یورو
معافیت = ۰ یورو
نرخ مالیات = ۴۱٪
مالیات = ۱۶٬۷۸۲ یورو
سربار = ۷٬۱۷۶ یورو
تخفیف = ۰ یورو
کاهش = ۰ یورو
نرخ مالیات = ۴۱٪
زوجی با سه فرزند و درآمد سالانه ۱۰۰,۰۰۰ یورو
مالیات = ۹٬۲۰۰ یورو
تخفیف = ۰ یورو
معافیت مالیاتی = ۰ یورو
نرخ مالیات = ۳۰٪
مالیات = ۹۲۰۰ یورو
سربار = ۲٬۱۸۰ یورو
تخفیف = ۰ یورو
کاهش = ۰ یورو
نرخ مالیات = ۳۰٪
زوجی با ۵ فرزند و درآمد سالانه ۱۰۰,۰۰۰ یورو
مالیات = ۴٬۲۳۰ یورو
تخفیف = ۰ یورو
معافیت مالیاتی = ۰ یورو
نرخ مالیات = ۱۴٪
مالیات = ۴۲۳۰ یورو
تخفیف = ۰ یورو
معافیت = ۰ یورو
نرخ مالیات = 14%
مجرد، بدون فرزند و با درآمد سالانه ۱۰۰,۰۰۰ یورو
مالیات = ۲۲٬۹۸۶ یورو
تخفیف = ۰ یورو
معافیت = ۰ یورو
نرخ مالیات = ۴۱٪
مالیات = ۲۲٬۹۸۶ یورو
سربار = ۰ یورو
تخفیف = ۰ یورو
کاهش = ۰ یورو
نرخ مالیات = ۴۱٪
زوجی با دو فرزند و درآمد سالانه ۳۰,۰۰۰ یورو
مالیات = ۰ یورو
تخفیف = ۰ یورو
معافیت مالیاتی = ۰ یورو
نرخ مالیات = ۰٪
مالیات = ۰ یورو
تخفیف = ۰ یورو
کاهش = ۰ یورو
نرخ مالیات = ۰٪
مجرد، بدون فرزند، با درآمد سالانه ۲۰۰,۰۰۰ یورو
مالیات = ۶۴٬۲۱۱ یورو
تخفیف = ۰ یورو
معافیت = ۰ یورو
نرخ مالیات = ۴۵٪
مالیات = ۶۴٬۲۱۰ یورو
سربار = ۷٬۴۹۸ یورو
تخفیف = ۰ یورو
کاهش = ۰ یورو
نرخ مالیات = ۴۵٪
زوجی با سه فرزند و درآمد سالانه ۲۰۰,۰۰۰ یورو
مالیات = ۴۲٬۸۴۳ یورو
تخفیف = ۰ یورو
معافیت مالیاتی = ۰ یورو
نرخ مالیات = ۴۱٪
مالیات = ۴۲٬۸۴۲ یورو
سربار = ۱۷٬۲۸۳ یورو
تخفیف = ۰ یورو
کاهش = ۰ یورو
نرخ مالیات = ۴۱٪

در بالا، «سربار» به مبلغ اضافی پرداختی توسط افراد با درآمد بالا به دلیل دو عامل اشاره دارد:

  • سقف ۱۰ درصدی معافیت درآمد سالانه؛
  • سقف کمک‌هزینه خانوادگی؛

این شاخص قابل تأیید نیست زیرا شبیه‌ساز سازمان مالیاتی آن را ارائه نمی‌دهد.

می‌توانیم ببینیم که الگوریتم موجود در سند، مبلغ مالیات را هر بار به درستی محاسبه می‌کند، هرچند با یک حاشیه خطای ۱ یورو. این حاشیه خطا ناشی از گرد کردن اعداد است. در برخی موارد، تمام مبالغ پولی به بالا و در موارد دیگر به پایین، تا نزدیک‌ترین یورو گرد می‌شوند. از آنجایی که من با قوانین رسمی آشنا نبودم، مبالغ پولی در الگوریتم سند گرد شده‌اند:

  • برای تخفیف‌ها و کاهش‌ها تا نزدیک‌ترین یورو گرد شده است؛
  • به نزدیک‌ترین یورو برای عوارض اضافی و مالیات نهایی؛

ما قصد داریم چندین نسخه از اپلیکیشن محاسبه مالیات را توسعه دهیم.

8.2. نسخه ۱

Image

8.2.1. اسکریپت اصلی

ما یک برنامهٔ اولیه ارائه می‌دهیم که در آن:

  • داده‌های مورد نیاز برای محاسبه مالیات به‌صورت کد سخت در برنامه به‌عنوان فهرست‌ها و ثابت‌ها درج شده‌اند؛
  • جزئیات مودیان مالیاتی (وضعیت تأهل، تعداد فرزندان، حقوق) در یک فایل متنی اول به نام [taxpayersdata.txt] ذخیره می‌شوند؛
  • نتایج محاسبه مالیات (وضعیت تأهل، تعداد فرزندان، حقوق، مالیات) در یک فایل متنی دوم به نام [résultats.txt] ذخیره می‌شوند؛

اسکریپت [v-01/main.py] به شرح زیر است:


#ماژول‌ها
import sys

from impots.v01.shared.impôts_module_01 import *

# main -----------------------

# ثوابت
# فایل مودیان
DATA = "./data/taxpayersdata.txt"
# فایل نتایج
RESULTATS = "./data/résultats.txt"

try:
    # خواندن داده‌های مودی
    tax_payers = get_taxpayers_data(DATA)
    # فهرست نتایج
    results = []
    #مالیات برای مودیان محاسبه می‌شود
    for tax_payer in tax_payers:
        # محاسبه مالیات یک دیکشنری کلید بازمی‌گرداند
        # ['marié', 'enfants', 'salaire', 'impôt', 'surcôte', 'décôte', 'réduction', 'taux']
        result = calcul_impôt(tax_payer['marié'], tax_payer['enfants'], tax_payer['salaire'])
        # واژه‌نامه به فهرست نتایج اضافه می‌شود
        results.append(result)
    #نتایج ذخیره می‌شوند
    record_results(RESULTATS, results)
except BaseException as erreur:
    #خطاهای مختلفی ممکن است رخ دهد: فایل یافت نشد، محتوای نادرست فایل
    #خطا نمایش داده می‌شود و برنامه بسته می‌شود
    print(f"l'erreur suivante s'est produite : {erreur}]\n")
    sys.exit()

یادداشت‌ها

  • خط ۴: از ماژول [impots.v01.modules.impôts_module_01] استفاده می‌شود. توجه داشته باشید که این مسیر از ریشه پروژه PyCharm اندازه‌گیری می‌شود؛
  • خط ۱۰: فایل [data/taxpayersdata.txt] به شرح زیر است:
oui,2,55555
oui,2,50000
oui,3,50000
non,2,100000
non,3,100000
oui,3,100000
oui,5,100000
non,0,100000
oui,2,30000
non,0,200000
oui,3,200000

هر خط نمایانگر یک تپلی از سه عنصر [marié / pacsé ou pas, nombre d'enfants, salaire annuel en euros] است.

  • خط ۱۲: فایلی که نتایج محاسبه مالیات برای هر مودی در فایل [taxpayersdata.txt] در آن قرار می‌گیرد. این فایل محتوای زیر را خواهد داشت:
{'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': 50000, 'impôt': 0, 'surcôte': 0, 'décôte': 720, 'réduction': 0, 'taux': 0.14}
{'marié': 'non', 'enfants': 2, 'salaire': 100000, 'impôt': 19884, 'surcôte': 4480, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'non', 'enfants': 3, 'salaire': 100000, 'impôt': 16782, 'surcôte': 7176, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'oui', 'enfants': 3, 'salaire': 100000, 'impôt': 9200, 'surcôte': 2180, 'décôte': 0, 'réduction': 0, 'taux': 0.3}
{'marié': 'oui', 'enfants': 5, 'salaire': 100000, 'impôt': 4230, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.14}
{'marié': 'non', 'enfants': 0, 'salaire': 100000, 'impôt': 22986, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'oui', 'enfants': 2, 'salaire': 30000, 'impôt': 0, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0}
{'marié': 'non', 'enfants': 0, 'salaire': 200000, 'impôt': 64210, 'surcôte': 7498, 'décôte': 0, 'réduction': 0, 'taux': 0.45}
{'marié': 'oui', 'enfants': 3, 'salaire': 200000, 'impôt': 42842, 'surcôte': 17283, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
  • خط ۱۶: داده‌های مودی مالیاتی موجود در [taxpayersdata.txt] بازیابی می‌شود. یک لیست از جفت‌های کلید-مقدار [marié, enfants, salaire] بازیابی می‌شود، که هر جفت کلید-مقدار نماینده یک مودی مالیاتی است؛
  • خطوط ۱۷–۲۵: مالیات مودیان در لیست [taxPayers] محاسبه می‌شود. یک لیست [results] بازیابی می‌شود که هر عنصر آن مجدداً یک فرهنگ لغت کلیدی [marié, enfants, salaire, impôt, surcôte, décôte, réduction, taux] است؛
  • خط ۲۷: لیست نتایج [results] در فایل [résultats.txt] با فرمت نشان داده شده در بالا نوشته می‌شود؛
  • خطوط ۲۸–۳۲: تمام استثناهایی که ممکن است توسط ماژول [impots.v01.modules.impôts_module_01] پرتاب شوند، گرفته می‌شوند؛

اکنون سه تابع مورد استفاده در اسکریپت [main] را به تفصیل توضیح می‌دهیم:

  • [get_taxpayers_data]: برای خواندن داده‌های مودی؛
  • [calcul_impôt]: برای محاسبه مالیات آنها؛
  • [record_results]: برای ذخیره نتایج در یک فایل متنی؛

تمام این توابع در ماژول [impots.modules.impôts_module_01] گنجانده شده‌اند.

8.2.2. ماژول [impots.v01.shared.impôts_module_01]

توابع مورد نیاز برای محاسبه مالیات در ماژول [impots.v01.shared.impôts_module_01] گردآوری شده‌اند:

Image

  • در [1]: تعریف ثابت‌ها برای محاسبه مالیات؛
  • در [2]: فهرست توابع در ماژول؛

8.2.3. تابع [get_taxpayers_data]

تابع [get_taxpayers_data] به شرح زیر است:


# واردات
import codecs


# خواندن داده‌های مالیات‌دهنده
# ----------------------------------------
def get_taxpayers_data(taxpayers_filename: str) -> list:
    # خواندن داده‌های مودی
    file = None
    try:
        # فهرست مودیان
        taxpayers = []
        # باز کردن فایل
        file = codecs.open(taxpayers_filename, "r", "utf8")
        # خواندن اولین خط فایل مودی
        ligne = file.readline().strip()
        #تا زمانی که یک خط برای پردازش باقی مانده باشد
        while ligne != '':
            # سه فیلد – «متأهل»، «فرزندان» و «حقوق» – را که این خط را تشکیل می‌دهند، بازیابی کنید
            (marié, enfants, salaire) = ligne.split(",")
            # آنها را به فهرست مالیات‌دهندگان اضافه می‌کنیم
            taxpayers.append({'marié': marié.strip().lower(), 'enfants': int(enfants), 'salaire': int(salaire)})
            #یک خط جدید از فایل مودیان می‌خوانیم
            ligne = file.readline().strip()
        #نتیجه بازگردانده می‌شود
        return taxpayers
    finally:
        # اگر فایل باز باشد، آن را ببندید
        if file:
            file.close()

یادداشت‌ها

  • خط ۷: [taxpayers_filename] نام فایلی است که باید پردازش شود. این تابع یک لیست بازمی‌گرداند؛
  • خطوط ۱۸–۲۴: حلقه خطوط [marié, enfants, salaire] فایل متنی را پردازش می‌کند؛
  • خط ۲۰: سه عنصر خط بازیابی می‌شوند. در اینجا فرض بر این است که خط از نظر نحوی صحیح است، یعنی واقعاً حاوی سه عنصر مورد انتظار است؛
  • خط ۲۲: یک دیکشنری با کلیدهای [marié, enfants, salaire] ساخته می‌شود، و این دیکشنری به لیست [taxPayers] اضافه می‌شود؛
  • خط ۲۶: پس از پردازش فایل، لیست [taxPayers] بازگردانده می‌شود؛
  • خطوط ۱۰–۳۰: توجه کنید که هیچ بند [catch] در خط ۱۰ به [try] اضافه نشده است. بند [catch] اجباری نیست. در خط ۲۷، یک بند [finally] برای بستن فایل متنی در همه موارد، چه خطایی رخ دهد یا نه، اضافه شده است؛
  • این ساختار try/finally به یک استثنای احتمالی اجازه می‌دهد تا فرار کند (هیچ بلوک catch وجود ندارد). این استثنا به اسکریپت اصلی [main] منتقل می‌شود که متوقف شده و استثنا را نمایش می‌دهد (به بخش |اسکریپت اصلی| مراجعه کنید). این مکانیزم برای اکثر توابع ماژول استفاده شده است؛

8.2.4. تابع [calcul_impôt]

تابع [calcul_impôt] به شرح زیر است:


# واردات‌ها
import codecs
import math

# محدوده‌های مالیاتی ۲۰۱۹
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


#محاسبه مالیات
# ----------------------------------------
def calcul_impôt(marié: str, enfants: int, salaire: int) -> dict:
    # متأهل: بله، خیر
    # فرزندان: تعداد فرزندان
    # حقوق: حقوق سالانه
    #آستانه‌ها، coeffr، coeffn: جداول داده‌ای مورد استفاده برای محاسبه مالیات
    #
    #محاسبه مالیات شامل فرزندان
    result1 = calcul_impôt_2(marié, enfants, salaire)
    impot1 = result1["impôt"]
    #محاسبه مالیات بدون احتساب فرزندان
    if enfants != 0:
        result2 = calcul_impôt_2(marié, 0, salaire)
        impot2 = result2["impôt"]
        # اعمال سقف ضریب خانوادگی
        if enfants < 3:
            # PLAFOND_QF_DEMI_PART یورو برای دو فرزند اول
            impot2 = impot2 - enfants * PLAFOND_QF_DEMI_PART
        else:
            #PLAFOND_QF_DEMI_PART یورو برای دو فرزند اول، دو برابر آن برای فرزندان بعدی
            impot2 = impot2 - 2 * PLAFOND_QF_DEMI_PART - (enfants - 2) * 2 * 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(marié, salaire, impot)
    impot -= décôte
    #محاسبه هرگونه معافیت مالیاتی
    réduction = get_réduction(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}

یادداشت‌ها

  • خطوط ۶–۸: معیارهای مالیاتی (به بخش |محاسبه مالیات ناخالص| مراجعه کنید)؛
  • خطوط ۱۱–۲۰: ثابت‌های مورد استفاده در محاسبه مالیات؛
  • توجه داشته باشید که متغیرهایی که در خطوط ۵ تا ۲۰ مقداردهی شده‌اند، برای توابع ما که در ادامه توضیح داده می‌شوند، سراسری (global) خواهند بود. بنابراین، تا زمانی که تابع استفاده کننده‌ای از آن‌ها، متغیرهایی با همان نام‌ها را تعریف نکند، این متغیرها قابل دسترس هستند؛
  • اعداد در خطوط ۵ تا ۲۰ هر سال تغییر می‌کنند. در اینجا، این اعداد مربوط به سال ۲۰۱۹ هستند؛
  • خط ۲۵: تابع [calcul_impôt] سه پارامتر می‌گیرد:
    • [marié]: بله/خیر، که نشان می‌دهد آیا مودی متأهل است یا در یک شراکت مدنی به سر می‌برد؛
    • [enfants]: تعداد فرزندان؛
    • [salaire]: حقوق سالانه آنها به یورو؛
  • رده‌های ۳۱–۳۳: محاسبه مالیات با در نظر گرفتن فرزندان؛
  • رده‌های ۳۴–۴۷: این رده‌ها سقف ضریب خانوادگی را اعمال می‌کنند (به بخش |سقف ضریب خانوادگی| مراجعه کنید)؛
  • رده‌های ۴۹–۵۷: این ردیف‌ها نرخ مالیاتی مودی و هرگونه مالیات اضافی را محاسبه می‌کنند (به بخش |موارد با درآمد بالا| مراجعه کنید)؛
  • رده‌های ۵۹–۶۱: محاسبه هرگونه بازپرداخت مالیاتی (به بخش |محاسبه بازپرداخت مالیاتی| مراجعه کنید)؛
  • خطوط ۶۲–۶۴: محاسبه هرگونه کاهش در مالیات پرداختنی (به بخش |محاسبه کاهش مالیات| مراجعه کنید)؛

الگوریتم بسیار پیچیده است و ما بیش از آنچه در توضیحات ارائه شده، وارد جزئیات نخواهیم شد. این الگوریتم روش محاسبه مالیات را همان‌طور که در بخش «مسئله» توضیح داده شده است، پیاده‌سازی می‌کند.

8.2.5. تابع [calcul_impôt_2]

تابع [calcul_impôt] تابع زیر را فراخوانی می‌کند: [calcul_impôt_2]:


def calcul_impôt_2(marié: str, enfants: int, salaire: int) -> list:
    # متأهل: بله، خیر
    # فرزندان: تعداد فرزندان
    # حقوق: حقوق سالانه
    # آستانه‌ها، ضریب: جداول داده‌ای مورد استفاده برای محاسبه مالیات
    #
    # تعداد سهام
    marié = marié.strip().lower()
    if marié == "oui":
        nb_parts = enfants / 2 + 2
    else:
        nb_parts = enfants / 2 + 1

    # به ازای هر فرزند از سوم به بعد، یک سهم
    if enfants >= 3:
        # نیم سهم اضافی برای هر فرزند از سوم به بعد
        nb_parts += 0.5 * (enfants - 2)

    # درآمد مشمول مالیات
    revenu_imposable = get_revenu_imposable(salaire)
    # سربار
    surcôte = math.floor(revenu_imposable - 0.9 * salaire)
    #برای مسائل گرد کردن
    if surcôte < 0:
        surcôte = 0

    # ضریب خانوادگی
    quotient = revenu_imposable / nb_parts
    #در انتهای جدول محدودیت‌ها قرار می‌گیرد تا حلقهٔ زیر را خاتمه دهد
    limites[len(limites) - 1] = quotient
    #محاسبه مالیات
    i = 0
    while quotient > limites[i]:
        i += 1
        # از آنجا که کسر خانواده در انتهای جدول محدودیت‌ها قرار داده شده است، حلقه قبلی
    # نمی‌تواند از آرایه محدودیت‌ها فراتر رود

    # اکنون می‌توانیم مالیات را محاسبه کنیم
    impôt = math.floor(revenu_imposable * coeffr[i] - nb_parts * coeffn[i])
    # نتیجه
    return {"impôt": impôt, "surcôte": surcôte, "taux": coeffr[i]}

این الگوریتم در بخش 8.1.1 توصیف شده است.

8.2.6. تابع [get_décôte]

تابع [get_décôte] محاسبه هرگونه تخفیف مالیاتی را پیاده‌سازی می‌کند (بخش |محاسبه تخفیف|):


#هرگونه تخفیف را محاسبه می‌کند
def get_décôte(marié: str, salaire: int, impots: int) -> int:
    # در ابتدا، تخفیف صفر
    décôte = 0
    #حداکثر مبلغ مالیات واجد شرایط برای معافیت مالیاتی
    plafond_impôt_pour_décôte = PLAFOND_IMPOT_COUPLE_POUR_DECOTE if marié == "oui" else PLAFOND_IMPOT_CELIBATAIRE_POUR_DECOTE
    if impots < plafond_impôt_pour_décôte:
        #حداکثر مبلغ کاهش
        plafond_décôte = PLAFOND_DECOTE_COUPLE if marié == "oui" else PLAFOND_DECOTE_CELIBATAIRE
        # تخفیف نظری
        décôte = plafond_décôte - 0.75 * impots
        # تخفیف نمی‌تواند از مبلغ مالیات تجاوز کند
        if décôte > impots:
            décôte = impots

        # بدون تخفیف <0
        if décôte < 0:
            décôte = 0

    # نتیجه
    return math.ceil(décôte)

8.2.7. تابع [get_réduction]

تابع [get_réduction] محاسبه هرگونه کاهش در مالیات پرداختنی را پیاده‌سازی می‌کند (بخش |محاسبه کاهش مالیات|):


#هرگونه کاهش را محاسبه می‌کند
def get_réduction(marié: str, salaire: int, enfants: int, impots: int) -> int:
    # آستانه درآمد برای برخورداری از کاهش ۲۰٪
    plafond_revenu_pour_réduction = PLAFOND_REVENUS_COUPLE_POUR_REDUCTION if marié == "oui" else PLAFOND_REVENUS_CELIBATAIRE_POUR_REDUCTION
    plafond_revenu_pour_réduction += enfants * VALEUR_REDUC_DEMI_PART
    if enfants > 2:
        plafond_revenu_pour_réduction += (enfants - 2) * VALEUR_REDUC_DEMI_PART

    # درآمد مشمول مالیات
    revenu_imposable = get_revenu_imposable(salaire)
    # کاهش
    réduction = 0
    if revenu_imposable < plafond_revenu_pour_réduction:
        # کاهش ۲۰ درصدی
        réduction = 0.2 * impots

    # نتیجه
    return math.ceil(réduction)

8.2.8. تابع [get_revenu_imposable]

توابع [get_revenu_imposable] درآمد مشمول مالیات را بر اساس حقوق سالانه محاسبه می‌کند:


# revenu_imposable = salaireAnnuel – معافیت
# مبلغ معافیت حداقل و حداکثری دارد
# ----------------------------------------
def get_revenu_imposable(salaire: int) -> int:
    # کسر ۱۰ درصد از حقوق
    abattement = 0.1 * salaire
    #این کسورات نمی‌تواند از ABATTEMENT_DIXPOURCENT_MAX فراتر رود
    if abattement > ABATTEMENT_DIXPOURCENT_MAX:
        abattement = ABATTEMENT_DIXPOURCENT_MAX

    # این فوق‌العاده نمی‌تواند کمتر از ABATTEMENT_DIXPOURCENT_MIN باشد
    if abattement < ABATTEMENT_DIXPOURCENT_MIN:
        abattement = ABATTEMENT_DIXPOURCENT_MIN

    #درآمد مشمول مالیات
    revenu_imposable = salaire - abattement
    # سود
    return math.floor(revenu_imposable)

8.2.9. تابع [record_results]

تابع [record_results] نتایج محاسبه مالیات را در یک فایل متنی ذخیره می‌کند:


# نوشتن نتایج در یک فایل متنی
# ----------------------------------------
def record_results(results_filename: str, results: list):
    # results_filename: نام فایل متنی برای ذخیره نتایج
    #نتایج: فهرست نتایج به صورت یک لیست از فرهنگ لغت‌ها
    # هر فرهنگ لغت در یک خط متنی نوشته می‌شود
    résultats = None
    try:
        # باز کردن فایل نتایج
        résultats = codecs.open(results_filename, "w", "utf8")
        #پردازش مودیان
        for result in results:
            # نتیجه در فایل نتایج نوشته می‌شود
            résultats.write(f"{result}\n")
            # مالیات‌دهنده بعدی
    finally:
        # در صورتی که فایل باز شده باشد، آن را ببندید
        if résultats:
            résultats.close()

8.2.10. نتایج

همان‌طور که قبلاً ذکر شد، با فایل مؤدی زیر [taxpayersdata.txt]:

oui,2,55555
oui,2,50000
oui,3,50000
non,2,100000
non,3,100000
oui,3,100000
oui,5,100000
non,0,100000
oui,2,30000
non,0,200000
oui,3,200000

اسکریپت [main.py] فایل زیر را ایجاد می‌کند: [résultats.txt]:

{'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': 50000, 'impôt': 0, 'surcôte': 0, 'décôte': 720, 'réduction': 0, 'taux': 0.14}
{'marié': 'non', 'enfants': 2, 'salaire': 100000, 'impôt': 19884, 'surcôte': 4480, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'non', 'enfants': 3, 'salaire': 100000, 'impôt': 16782, 'surcôte': 7176, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'oui', 'enfants': 3, 'salaire': 100000, 'impôt': 9200, 'surcôte': 2180, 'décôte': 0, 'réduction': 0, 'taux': 0.3}
{'marié': 'oui', 'enfants': 5, 'salaire': 100000, 'impôt': 4230, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.14}
{'marié': 'non', 'enfants': 0, 'salaire': 100000, 'impôt': 22986, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0.41}
{'marié': 'oui', 'enfants': 2, 'salaire': 30000, 'impôt': 0, 'surcôte': 0, 'décôte': 0, 'réduction': 0, 'taux': 0}
{'marié': 'non', 'enfants': 0, 'salaire': 200000, 'impôt': 64210, 'surcôte': 7498, 'décôte': 0, 'réduction': 0, 'taux': 0.45}
{'marié': 'oui', 'enfants': 3, 'salaire': 200000, 'impôt': 42842, 'surcôte': 17283, 'décôte': 0, 'réduction': 0, 'taux': 0.41}

این نتایج با ارقام رسمی در بخش |Official figures| مطابقت دارد.

اکنون، بیایید این نسخه را در یک پنجره کنسول اجرا کنیم:


(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\impots\v01>python main.py
Traceback (most recent call last):
  File "main.py", line 4, in <module>
    from impots.v01.shared.impôts_module_01 import *
ModuleNotFoundError: No module named 'impots'

ما با خطایی مواجه می‌شویم که قبلاً دیده‌ایم: خطایی که در آن ماژولی پیدا نمی‌شود، در این مورد ماژول [impots]. به عنوان یادآوری، این بدان معناست که:

  • تفسیرگر پایتون دایرکتوری‌های موجود در مسیر پایتون را یکی‌یکی جستجو کرده است؛
  • در هیچ‌کدام از آن‌ها پوشه‌ای حاوی اسکریپتی با نام [impots.py] پیدا نکرد؛

نسخه [v02] این مشکل را برطرف خواهد کرد.