8. تمرين تطبيقي – الإصدار 1
8.1. المشكلة
يتيح لنا الجدول أعلاه حساب الضريبة في الحالة المبسطة للمكلف الذي لا يبلغ سوى عن راتبه. وكما هو موضح في الملاحظة (1)، فإن الضريبة المحسوبة بهذه الطريقة هي الضريبة قبل تطبيق الآليات الثلاث التالية:
- سقف الحصة العائلية، الذي ينطبق على الدخل المرتفع؛
- الائتمان الضريبي والتخفيض الضريبي اللذان ينطبقان على الدخل المنخفض؛
وبالتالي، يتضمن حساب الضريبة الخطوات التالية [http://impotsurlerevenu.org/comprendre-le-calcul-de-l-impot/1217-calcul-de-l-impot-2019.php]:

نقترح كتابة برنامج لحساب ضريبة دافع الضرائب في الحالة المبسطة لدافع الضرائب الذي لا يبلغ سوى عن راتبه:
8.1.1. حساب الضريبة الإجمالية
يمكن حساب الضريبة الإجمالية على النحو التالي:
أولاً، نحسب عدد الأسهم الخاصة بالمكلف:
- يساهم كل من الوالدين بحصة واحدة؛
- يساهم كل من الطفلين الأولين بنصف سهم؛
- ويساهم كل طفل من الأطفال التاليين بحصة واحدة:
وبالتالي، يكون عدد الأسهم:
- nbParts=1+nbChildren*0.5+(nbChildren-2)*0.5 إذا كان الموظف غير متزوج؛
- nbParts=2+nbChildren*0.5+(nbChildren-2)*0.5 إذا كان متزوجًا؛
- حيث nbChildren هو عدد الأطفال؛
- نحسب الدخل الخاضع للضريبة R = 0.9 * S، حيث S هو الراتب السنوي؛
- يُحسب معامل الأسرة QF على النحو التالي: QF = R / nbParts؛
- نحسب الضريبة الإجمالية I بناءً على البيانات التالية (2019):
9964 | 0 | 0 |
27,519 | 0.14 | 1,394.96 |
73,779 | 0.3 | 5,798 |
156,244 | 0.4 | 13,913.69 |
0 | 0.45 | 20163.45 |
يحتوي كل صف على 3 حقول: الحقل 1، الحقل 2، الحقل 3. لحساب الضريبة I، نبحث عن الصف الأول الذي يكون فيه QF <= الحقل 1 ونأخذ القيم من ذلك الصف. على سبيل المثال، بالنسبة لموظف متزوج ولديه طفلان وراتب سنوي S قدره 50,000 يورو:
الدخل الخاضع للضريبة: R=0.9*S=45,000
عدد الحصص: nbParts=2+2*0.5=3
نسبة الأسرة: QF = 45,000 / 3 = 15,000
الصف الأول الذي يكون فيه QF <= field1 هو كما يلي:
وبالتالي، فإن الضريبة I تساوي 0.14*R – 1394.96*عدد_الأسهم=[0.14*45000-1394.96*3]=2115. يتم تقريب الضريبة لأسفل إلى أقرب يورو.
إذا كان الشرط QF <= field1 صحيحًا في الصف الأول، فإن الضريبة تساوي صفرًا.
إذا كان QF بحيث لا تتحقق الشرط QF <= field1 أبدًا، يتم استخدام المعاملات من السطر الأخير. هنا:
مما يعطي الضريبة الإجمالية I = 0.45*R – 20163.45*nbParts.
8.1.2. الحد الأقصى لنسبة الأسرة
لتحديد ما إذا كان الحد الأقصى لمعدل الأسرة (QF) ينطبق، نعيد حساب الضريبة الإجمالية بدون الأطفال. مرة أخرى، بالنسبة للموظف المتزوج الذي لديه طفلان وراتب سنوي S قدره 50,000 يورو:
الدخل الخاضع للضريبة: R = 0.9 * S = 45,000
عدد الحصص: nbParts=2 (لم يعد يتم احتساب الأطفال)
معدل الأسرة: QF = 45,000 / 2 = 22,500
السطر الأول حيث QF <= field1 هو كما يلي:
وبالتالي، فإن الضريبة الأولى تساوي 0.14*R – 1394.96*عدد الأسهم = [0.14*45,000 – 1394.96*2] = 3,510.
الحد الأقصى للإعانة المتعلقة بالأطفال: 1551 * 2 = 3102 يورو
الضريبة الدنيا: 3,510 – 3,102 = 408 يورو
الضريبة الإجمالية مع 3 شرائح ضريبية، التي تم حسابها بالفعل بمبلغ 2,115 يورو، أعلى من الحد الأدنى للضريبة البالغ 408 يورو، لذا لا ينطبق سقف الأسرة هنا.
بشكل عام، يكون إجمالي الضريبة أكبر من (الضريبة 1، الضريبة 2) حيث:
- [الضريبة 1]: هي الضريبة الإجمالية المحسوبة بما في ذلك الأطفال؛
- [الضريبة 2]: هي الضريبة الإجمالية المحسوبة بدون الأطفال ومخصومة منها الائتمان الأقصى (هنا 1,551 يورو لكل نصف حصة) المتعلق بالأطفال؛
8.1.3. حساب التخفيض

باستخدام المثال نفسه لموظف متزوج ولديه طفلان وراتب سنوي S قدره 50,000 يورو:
الضريبة الإجمالية (2,115) من الخطوة السابقة أقل من 2,627 يورو للزوجين (1,595 يورو للشخص العازب): وبالتالي ينطبق التخفيض. ويتم حسابه على النحو التالي:
الخصم = الحد الأدنى (للزوجين = 1,970 / للأعزب = 1,196) - 0.75 * الضريبة الإجمالية
الخصم = 1,970 – 0.75 * 2,115 = 383.75، مقربًا إلى 384 يورو.
الضريبة الإجمالية الجديدة = 2,115 – 384 = 1,731 يورو
8.1.4. حساب التخفيض الضريبي

تحت حد معين، يتم تطبيق تخفيض بنسبة 20% على الضريبة الإجمالية الناتجة عن الحسابات السابقة. في عام 2019، كانت الحدود كما يلي:
- الأفراد: 21,037 يورو؛
- الأزواج: 42,074 يورو؛ (يبدو أن الرقم 37,968 المستخدم في المثال أعلاه غير صحيح)؛
يتم زيادة هذا الحد بقيمة: 3,797 * (عدد نصف الحصص التي يساهم بها الأبناء).
مرة أخرى، بالنسبة للموظف المتزوج الذي لديه طفلان وراتب سنوي S قدره 50,000 يورو:
- دخله الخاضع للضريبة (45,000 يورو) أقل من الحد الأدنى (42,074 + 2 × 3,797) = 49,668 يورو؛
- وبالتالي يحق له الحصول على تخفيض بنسبة 20% في ضريبته: 1,731 * 0.2 = 346.2 يورو، مقربًا إلى 347 يورو؛
- يصبح إجمالي الضريبة المستحقة على المكلف: 1,731 – 347 = 1,384 يورو؛
8.1.5. حساب صافي الضريبة
وينتهي حسابنا هنا: سيكون صافي الضريبة المستحقة 1,384 يورو. وفي الواقع، قد يكون المكلف مؤهلاً للحصول على خصومات أخرى، لا سيما تلك المتعلقة بالتبرعات المقدمة إلى المنظمات العامة أو ذات المنفعة العامة.
8.1.6. حالات الدخل المرتفع
ينطبق المثال السابق على غالبية الموظفين. ومع ذلك، يختلف حساب الضريبة بالنسبة لأصحاب الدخل المرتفع.
8.1.6.1. الحد الأقصى للتخفيض بنسبة 10% على الدخل السنوي
في معظم الحالات، يُحسب الدخل الخاضع للضريبة باستخدام الصيغة: R = 0.9 × S، حيث S هو الراتب السنوي. يُعرف هذا باسم التخفيض بنسبة 10٪. هذا التخفيض محدد بسقف. في عام 2019:
- لا يمكن أن يتجاوز 12,502 يورو؛
- لا يمكن أن يقل عن 437 يورو؛
لنأخذ مثالاً لموظف غير متزوج وليس لديه أطفال ويبلغ راتبه السنوي 200,000 يورو:
- تبلغ نسبة التخفيض البالغة 10% 200,000 يورو > 12,502 يورو. وبالتالي، فإن الحد الأقصى هو 12,502 يورو؛
8.1.6.2. الحد الأقصى لمعدل الأسرة
لنأخذ حالة ينطبق عليها الحد الأقصى للأسرة الموصوف في القسم |الحد الأقصى لمعدل الأسرة|. لنأخذ حالة زوجين لديهما ثلاثة أطفال ودخل سنوي قدره 100,000 يورو. لنراجع خطوات الحساب مرة أخرى:
- الخصم بنسبة 10% هو 10,000 يورو < 12,502 يورو. وبالتالي، فإن الدخل الخاضع للضريبة R هو 100,000 - 10,000 = 90,000 يورو؛
- لدى الزوجين 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 = 90,000 / 2 = 45,000 يورو؛
- I2 = 0.3 × 90,000 – 5,798 × 2 = 15,404 يورو؛
- تنص قاعدة سقف الحصة العائلية على أن المزايا التي يوفرها الأطفال لا يمكن أن تتجاوز (1,551 × 4 نصف حصص) = 6,204 يورو. ومع ذلك، في هذه الحالة، فإن I2 – I1 = 15,404 – 7,020 = 8,384 يورو، وهو مبلغ أكبر من 6,204 يورو؛
- وبالتالي، يُعاد حساب الضريبة الإجمالية على النحو التالي: I3 = I2 - 6,204 = 15,404 - 6,204 = 9,200 يورو؛
لن يحصل هذا الزوجان على أي خصم ضريبي أو تخفيض، وستكون ضريبتهم النهائية 9,200 يورو.
8.1.7. الأرقام الرسمية
يعد حساب الضرائب أمرًا معقدًا. في هذا المستند، ستستند الحسابات إلى الأمثلة التالية. النتائج مأخوذة من أداة المحاكاة الخاصة بالسلطة الضريبية |https://www3.impots.gouv.fr/simulateur/calcul_impot/2019/simplifie/index.htm|:
المكلف | النتائج الرسمية | النتائج المستمدة من خوارزمية الوثيقة |
زوجان لديهما طفلان ودخلهما السنوي 55,555 يورو | الضريبة = 2,815 يورو معدل الضريبة = 14% | الضريبة = 2,814 يورو معدل الضريبة = 14% |
زوجان ولديهما طفلان ودخل سنوي يبلغ 50,000 يورو ( ) | الضريبة = 1,385 يورو الائتمان الضريبي = 720 يورو التخفيض = 0 يورو معدل الضريبة = 14% | الضريبة = 1,384 يورو الخصم = 384 يورو الائتمان = 347 يورو معدل الضريبة = 14% |
زوجان ولديهما 3 أطفال ودخلهما السنوي 50,000 يورو | الضريبة = 0 يورو الائتمان الضريبي = 384 يورو التخفيض = 346 يورو معدل الضريبة = 14% | الضريبة = 0 يورو الخصم = 720 يورو الخصم = 0 يورو معدل الضريبة = 14% |
أعزب ولديه طفلان ودخله السنوي 100,000 يورو | الضريبة = 19,884 يورو الائتمان الضريبي = 0 يورو الخصم = 0 يورو معدل الضريبة = 41% | الضريبة = 19,884 يورو الرسوم الإضافية = 4,480 يورو الخصم = 0 يورو التخفيض = 0 يورو معدل الضريبة = 41% |
أعزب ولديه 3 أطفال ودخله السنوي 100,000 يورو | الضريبة = 16,782 يورو الائتمان الضريبي = 0 يورو الخصم = 0 يورو معدل الضريبة = 41% | الضريبة = 16,782 يورو الرسوم الإضافية = 7,176 يورو الخصم = 0 يورو التخفيض = 0 يورو معدل الضريبة = 41% |
زوجان ولديهما 3 أطفال ودخلهما السنوي 100,000 يورو | الضريبة = 9,200 يورو الائتمان الضريبي = 0 يورو الخصم = 0 يورو معدل الضريبة = 30% | الضريبة = 9,200 يورو الرسوم الإضافية = 2,180 يورو الخصم = 0 يورو التخفيض = 0 يورو معدل الضريبة = 30% |
زوجان لديهما 5 أطفال ودخل سنوي قدره 100,000 يورو | الضريبة = 4,230 يورو الائتمان الضريبي = 0 يورو الخصم = 0 يورو معدل الضريبة = 14% | الضريبة = 4,230 يورو الخصم = 0 يورو الخصم = 0 يورو معدل الضريبة = 14% |
أعزب، بدون أطفال، ودخل سنوي قدره 100,000 يورو | الضريبة = 22,986 يورو الائتمان الضريبي = 0 يورو الخصم = 0 يورو معدل الضريبة = 41% | الضريبة = 22,986 يورو الرسوم الإضافية = 0 يورو الخصم = 0 يورو التخفيض = 0 يورو معدل الضريبة = 41% |
زوجان ولديهما طفلان ودخلهما السنوي 30,000 يورو | الضريبة = 0 يورو الائتمان الضريبي = 0 يورو الخصم = 0 يورو معدل الضريبة = 0% | الضريبة = 0 يورو الخصم = 0 يورو التخفيض = 0 يورو معدل الضريبة = 0% |
أعزب بدون أطفال ودخل سنوي قدره 200,000 يورو | الضريبة = 64,211 يورو الائتمان الضريبي = 0 يورو الخصم = 0 يورو معدل الضريبة = 45% | الضريبة = 64,210 يورو الرسوم الإضافية = 7,498 يورو الخصم = 0 يورو التخفيض = 0 يورو معدل الضريبة = 45% |
زوجان ولديهما 3 أطفال ودخلهما السنوي 200,000 يورو | الضريبة = 42,843 يورو الائتمان الضريبي = 0 يورو الخصم = 0 يورو معدل الضريبة = 41% | الضريبة = 42,842 يورو الرسوم الإضافية = 17,283 يورو الخصم = 0 يورو التخفيض = 0 يورو معدل الضريبة = 41% |
في المثال أعلاه، تشير "الرسوم الإضافية" إلى المبلغ الإضافي الذي يدفعه أصحاب الدخل المرتفع بسبب عاملين:
- الحد الأقصى للخصم بنسبة 10٪ من الدخل السنوي؛
- الحد الأقصى لبدل الأسرة؛
لم يتسن التحقق من هذا المؤشر لأن أداة المحاكاة الخاصة بالسلطة الضريبية لا توفره.
يمكننا أن نلاحظ أن خوارزمية الوثيقة تحسب المبلغ الضريبي الصحيح في كل مرة، وإن كان ذلك مع هامش خطأ قدره 1 يورو. وينشأ هامش الخطأ هذا عن التقريب. فجميع المبالغ النقدية يتم تقريبها لأعلى إلى أقرب يورو في بعض الحالات، ولأسفل إلى أقرب يورو في حالات أخرى. وبما أنني لم أكن على دراية بالقواعد الرسمية، فقد تم تقريب المبالغ النقدية في خوارزمية الوثيقة:
- إلى اليورو الأعلى في حالة الخصومات والتخفيضات؛
- للأسفل إلى أقرب يورو للرسوم الإضافية والضريبة النهائية؛
سنقوم بتطوير عدة إصدارات من تطبيق حساب الضريبة.
8.2. الإصدار 1

8.2.1. النص الرئيسي
نقدم برنامجًا أوليًا حيث:
- البيانات اللازمة لحساب الضريبة مدمجة في الكود كقوائم وثوابت؛
- يتم تخزين بيانات دافعي الضرائب (متزوج، أطفال، راتب) في ملف نصي أول [taxpayersdata.txt]؛
- يتم تخزين نتائج حساب الضريبة (متزوج، أطفال، راتب، ضريبة) في ملف نصي ثانٍ [results.txt]؛
النص البرمجي [v-01/main.py] هو كما يلي:
ملاحظات
- السطر 4: نستخدم الوحدة النمطية [impots.v01.modules.impôts_module_01]. لاحظ أن هذا المسار نسبي بالنسبة إلى جذر مشروع PyCharm؛
- السطر 10: الملف [data/taxpayersdata.txt] كما يلي:
يمثل كل سطر مجموعة مكونة من ثلاثة عناصر [متزوج/في شراكة مدنية أم لا، عدد الأبناء، الراتب السنوي باليورو].
- السطر 12: الملف الذي سيتم فيه وضع نتائج حساب الضريبة لكل دافع ضرائب في الملف [taxpayersdata.txt]. وسيحتوي على المحتوى التالي:
- السطر 16: نسترد بيانات دافعي الضرائب الموجودة في [taxpayersdata.txt]. نسترد قائمة من القواميس ذات المفاتيح [married, children, salary]، حيث يمثل كل قاموس دافع ضرائب؛
- الأسطر 17-25: يتم حساب الضريبة للمكلفين في قائمة [taxPayers]. يتم إرجاع قائمة [results]، حيث يكون كل عنصر عبارة عن قاموس بمفاتيح [married, children, salary, tax, surcharge, discount, reduction, rate]؛
- السطر 27: يتم حفظ قائمة [results] في الملف [results.txt] بالتنسيق الموضح أعلاه؛
- الأسطر 28–32: نلتقط جميع الاستثناءات التي قد تطرحها الوحدة النمطية [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]:

- في [1]: تعريف ثوابت حساب الضرائب؛
- في [2]: قائمة الوظائف الموجودة في الوحدة النمطية؛
8.2.3. الدالة [get_taxpayers_data]
وظيفة [get_taxpayers_data] هي كما يلي:
ملاحظات
- السطر 7: [taxpayers_filename] هو اسم الملف المراد معالجته. تُرجع الدالة قائمة؛
- الأسطر 18–24: تعالج الحلقة أسطر [married, children, salary] في الملف النصي؛
- السطر 20: يتم استرداد العناصر الثلاثة للسطر. نفترض هنا أن السطر صحيح من الناحية النحوية، أي أنه يحتوي بالفعل على العناصر الثلاثة المتوقعة؛
- السطر 22: يتم إنشاء قاموس بمفاتيح [married, children, salary]، ويتم إضافة هذا القاموس إلى القائمة [taxPayers]؛
- السطر 26: بمجرد معالجة الملف، يتم إرجاع قائمة [taxPayers]؛
- الأسطر 10–30: لاحظ أنه لم تتم إضافة جملة [catch] إلى كتلة [try] في السطر 10. جملة [catch] ليست إلزامية. في السطر 27، تمت إضافة جملة [finally] لإغلاق الملف النصي في جميع الحالات، سواء حدث خطأ أم لا؛
- تسمح بنية try/finally هذه بمرور استثناء محتمل (لا يوجد catch). سينتقل هذا الاستثناء إلى البرنامج النصي الرئيسي [main]، الذي سيتوقف ويعرض الاستثناء (انظر القسم |البرنامج النصي الرئيسي|). تم استخدام هذه الآلية في معظم وظائف الوحدة النمطية؛
8.2.4. وظيفة [calcul_impôt]
وظيفة [calcul_impôt] هي كما يلي:
ملاحظات
- الأسطر 6–8: شرائح الضريبة (انظر قسم |حساب الضريبة الإجمالية|)؛
- الأسطر 11–20: الثوابت لحساب الضريبة؛
- لاحظ أن العناصر التي تم تهيئتها في الأسطر 5–20 ستكون عامة بالنسبة للوظائف التي سنصفها. وبالتالي فهي معروفة طالما أن الوظيفة التي تستخدمها لا تعلن متغيرات تحمل نفس الأسماء؛
- تتغير الأرقام في الأسطر 5–20 كل عام. هنا، هي أرقام عام 2019؛
- السطر 25: تأخذ الدالة [calculate_tax] ثلاثة معلمات:
- [married]: نعم/لا، تشير إلى ما إذا كان دافع الضرائب متزوجًا أو في شراكة مدنية؛
- [children]: عدد الأطفال؛
- [salary]: راتبهم السنوي باليورو؛
- الأسطر 31-33: حساب الضريبة مع أخذ عدد الأطفال في الاعتبار؛
- الأسطر 34-47: تطبق هذه الأسطر الحد الأقصى لمعدل الأسرة (انظر القسم |الحد الأقصى لمعدل الأسرة|)؛
- الأسطر 49-57: تحسب هذه الأسطر معدل الضريبة على المكلف بالضريبة بالإضافة إلى أي رسوم إضافية (انظر القسم |حالات الدخل المرتفع|)؛
- الأسطر 59-61: حساب أي ائتمان ضريبي (انظر القسم |حساب الائتمان الضريبي|)؛
- الأسطر 62–64: حساب أي تخفيض في الضريبة المستحقة (انظر القسم |حساب التخفيض الضريبي|)؛
الخوارزمية معقدة للغاية، ولن ندخل في تفاصيل أكثر مما هو مذكور في التعليقات. تنفذ الخوارزمية طريقة حساب الضريبة كما هو موضح في القسم |المشكلة|.
8.2.5. دالة [calcul_tax_2]
تستدعي الدالة [calcul_impôt] الدالة التالية [calcul_impôt_2]:
تم وصف هذه الخوارزمية في القسم 8.1.1.
8.2.6. دالة [get_discount]
تقوم الدالة [get_discount] بتنفيذ حساب أي خصم ضريبي (القسم |حساب الخصم|):
8.2.7. دالة [get_reduction]
تقوم الدالة [get_reduction] بتنفيذ حساب أي تخفيض ضريبي (القسم |حساب التخفيض الضريبي|):
8.2.8. دالة [get_taxable_income]
تحسب الدالة [get_taxable_income] الدخل الخاضع للضريبة بناءً على الراتب السنوي:
8.2.9. وظيفة [record_results]
تقوم الدالة [record_results] بحفظ نتائج حساب الضريبة في ملف نصي:
8.2.10. النتائج
كما ذكرنا سابقًا، باستخدام ملف دافعي الضرائب التالي [taxpayersdata.txt]:
ينشئ البرنامج النصي [main.py] الملف التالي [results.txt]:
تتطابق هذه النتائج مع الأرقام الرسمية الواردة في قسم |الأرقام الرسمية|.
الآن، دعونا نشغل هذه النسخة في نافذة وحدة التحكم:
(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] النمطية. تذكر أن هذا يعني:
- أن مترجم Python قد بحث في الدلائل الموجودة في مسار Python واحدًا تلو الآخر؛
- ولم يعثر في أي منها على دليل يحتوي على البرنامج النصي [impots.py]؛
ستوفر النسخة [v02] حلاً لهذه المشكلة.