From 5e96a46c87e8eb861a81d74e45910187758f9c57 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 11 May 2022 16:45:20 +0530 Subject: [PATCH] test: HRA Exemption in Employee Tax Exemption Declaration --- ...test_employee_tax_exemption_declaration.py | 283 +++++++++++++++++- .../salary_structure/test_salary_structure.py | 9 +- 2 files changed, 288 insertions(+), 4 deletions(-) diff --git a/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py b/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py index 1d90e7383fe..6986bce6709 100644 --- a/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py +++ b/erpnext/payroll/doctype/employee_tax_exemption_declaration/test_employee_tax_exemption_declaration.py @@ -4,13 +4,15 @@ import unittest import frappe +from frappe.tests.utils import FrappeTestCase +from frappe.utils import add_months, getdate import erpnext from erpnext.hr.doctype.employee.test_employee import make_employee from erpnext.hr.utils import DuplicateDeclarationError -class TestEmployeeTaxExemptionDeclaration(unittest.TestCase): +class TestEmployeeTaxExemptionDeclaration(FrappeTestCase): def setUp(self): make_employee("employee@taxexepmtion.com") make_employee("employee1@taxexepmtion.com") @@ -112,6 +114,257 @@ class TestEmployeeTaxExemptionDeclaration(unittest.TestCase): self.assertEqual(declaration.total_exemption_amount, 100000) + def test_india_hra_exemption(self): + setup_hra_exemption_prerequisites("Monthly") + employee = frappe.get_value("Employee", {"user_id": "employee@taxexepmtion.com"}, "name") + + declaration = frappe.get_doc( + { + "doctype": "Employee Tax Exemption Declaration", + "employee": employee, + "company": "Test Company", + "payroll_period": "_Test Payroll Period 1", + "currency": "INR", + "monthly_house_rent": 50000, + "rented_in_metro_city": 1, + "declarations": [ + dict( + exemption_sub_category="_Test Sub Category", + exemption_category="_Test Category", + amount=80000, + ), + dict( + exemption_sub_category="_Test1 Sub Category", + exemption_category="_Test Category", + amount=60000, + ), + ], + } + ).insert() + + # Monthly HRA received = 3000 + # should set HRA exemption as per actual annual HRA because that's the minimum + self.assertEqual(declaration.monthly_hra_exemption, 3000) + self.assertEqual(declaration.annual_hra_exemption, 36000) + # 100000 Standard Exemption + 36000 HRA exemption + self.assertEqual(declaration.total_exemption_amount, 136000) + + def test_india_hra_exemption_with_daily_payroll_frequency(self): + setup_hra_exemption_prerequisites("Daily") + employee = frappe.get_value("Employee", {"user_id": "employee@taxexepmtion.com"}, "name") + + declaration = frappe.get_doc( + { + "doctype": "Employee Tax Exemption Declaration", + "employee": employee, + "company": "Test Company", + "payroll_period": "_Test Payroll Period 1", + "currency": "INR", + "monthly_house_rent": 170000, + "rented_in_metro_city": 1, + "declarations": [ + dict( + exemption_sub_category="_Test1 Sub Category", + exemption_category="_Test Category", + amount=60000, + ), + ], + } + ).insert() + + # Daily HRA received = 3000 + # should set HRA exemption as per (rent - 10% of Basic Salary), that's the minimum + self.assertEqual(declaration.monthly_hra_exemption, 17916.67) + self.assertEqual(declaration.annual_hra_exemption, 215000) + # 50000 Standard Exemption + 215000 HRA exemption + self.assertEqual(declaration.total_exemption_amount, 265000) + + def test_india_hra_exemption_with_weekly_payroll_frequency(self): + setup_hra_exemption_prerequisites("Weekly") + employee = frappe.get_value("Employee", {"user_id": "employee@taxexepmtion.com"}, "name") + + declaration = frappe.get_doc( + { + "doctype": "Employee Tax Exemption Declaration", + "employee": employee, + "company": "Test Company", + "payroll_period": "_Test Payroll Period 1", + "currency": "INR", + "monthly_house_rent": 170000, + "rented_in_metro_city": 1, + "declarations": [ + dict( + exemption_sub_category="_Test1 Sub Category", + exemption_category="_Test Category", + amount=60000, + ), + ], + } + ).insert() + + # Weekly HRA received = 3000 + # should set HRA exemption as per actual annual HRA because that's the minimum + self.assertEqual(declaration.monthly_hra_exemption, 13000) + self.assertEqual(declaration.annual_hra_exemption, 156000) + # 50000 Standard Exemption + 156000 HRA exemption + self.assertEqual(declaration.total_exemption_amount, 206000) + + def test_india_hra_exemption_with_fortnightly_payroll_frequency(self): + setup_hra_exemption_prerequisites("Fortnightly") + employee = frappe.get_value("Employee", {"user_id": "employee@taxexepmtion.com"}, "name") + + declaration = frappe.get_doc( + { + "doctype": "Employee Tax Exemption Declaration", + "employee": employee, + "company": "Test Company", + "payroll_period": "_Test Payroll Period 1", + "currency": "INR", + "monthly_house_rent": 170000, + "rented_in_metro_city": 1, + "declarations": [ + dict( + exemption_sub_category="_Test1 Sub Category", + exemption_category="_Test Category", + amount=60000, + ), + ], + } + ).insert() + + # Fortnightly HRA received = 3000 + # should set HRA exemption as per actual annual HRA because that's the minimum + self.assertEqual(declaration.monthly_hra_exemption, 6500) + self.assertEqual(declaration.annual_hra_exemption, 78000) + # 50000 Standard Exemption + 78000 HRA exemption + self.assertEqual(declaration.total_exemption_amount, 128000) + + def test_india_hra_exemption_with_bimonthly_payroll_frequency(self): + setup_hra_exemption_prerequisites("Bimonthly") + employee = frappe.get_value("Employee", {"user_id": "employee@taxexepmtion.com"}, "name") + + declaration = frappe.get_doc( + { + "doctype": "Employee Tax Exemption Declaration", + "employee": employee, + "company": "Test Company", + "payroll_period": "_Test Payroll Period 1", + "currency": "INR", + "monthly_house_rent": 50000, + "rented_in_metro_city": 1, + "declarations": [ + dict( + exemption_sub_category="_Test Sub Category", + exemption_category="_Test Category", + amount=80000, + ), + dict( + exemption_sub_category="_Test1 Sub Category", + exemption_category="_Test Category", + amount=60000, + ), + ], + } + ).insert() + + # Bimonthly HRA received = 3000 + # should set HRA exemption as per actual annual HRA because that's the minimum + self.assertEqual(declaration.monthly_hra_exemption, 1500) + self.assertEqual(declaration.annual_hra_exemption, 18000) + # 100000 Standard Exemption + 18000 HRA exemption + self.assertEqual(declaration.total_exemption_amount, 118000) + + def test_india_hra_exemption_with_multiple_salary_structure_assignments(self): + from erpnext.payroll.doctype.salary_slip.test_salary_slip import create_tax_slab + from erpnext.payroll.doctype.salary_structure.test_salary_structure import ( + create_salary_structure_assignment, + make_salary_structure, + ) + + payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company") + + create_tax_slab( + payroll_period, + allow_tax_exemption=True, + currency="INR", + effective_date=getdate("2019-04-01"), + company="_Test Company", + ) + + frappe.db.set_value( + "Company", "_Test Company", {"basic_component": "Basic Salary", "hra_component": "HRA"} + ) + + employee = frappe.get_value("Employee", {"user_id": "employee@taxexepmtion.com"}, "name") + + # salary structure with base 50000, HRA 3000 + make_salary_structure( + "Monthly Structure for HRA Exemption 1", + "Monthly", + employee=employee, + company="_Test Company", + currency="INR", + payroll_period=payroll_period.name, + from_date=payroll_period.start_date, + ) + + # salary structure with base 70000, HRA = base * 0.2 = 14000 + salary_structure = make_salary_structure( + "Monthly Structure for HRA Exemption 2", + "Monthly", + employee=employee, + company="_Test Company", + currency="INR", + payroll_period=payroll_period.name, + from_date=payroll_period.start_date, + dont_submit=True, + ) + for component_row in salary_structure.earnings: + if component_row.salary_component == "HRA": + component_row.amount = 0 + component_row.amount_based_on_formula = 1 + component_row.formula = "base * 0.2" + break + + salary_structure.submit() + + create_salary_structure_assignment( + employee, + salary_structure.name, + from_date=add_months(payroll_period.start_date, 6), + company="_Test Company", + currency="INR", + payroll_period=payroll_period.name, + base=70000, + allow_duplicate=True, + ) + + declaration = frappe.get_doc( + { + "doctype": "Employee Tax Exemption Declaration", + "employee": employee, + "company": "Test Company", + "payroll_period": "_Test Payroll Period 1", + "currency": "INR", + "monthly_house_rent": 50000, + "rented_in_metro_city": 1, + "declarations": [ + dict( + exemption_sub_category="_Test1 Sub Category", + exemption_category="_Test Category", + amount=60000, + ), + ], + } + ).insert() + + # Monthly HRA received = 50000 * 6 months + 70000 * 6 months + # should set HRA exemption as per actual annual HRA because that's the minimum + self.assertEqual(declaration.monthly_hra_exemption, 8500) + self.assertEqual(declaration.annual_hra_exemption, 102000) + # 50000 Standard Exemption + 102000 HRA exemption + self.assertEqual(declaration.total_exemption_amount, 152000) + def create_payroll_period(**args): args = frappe._dict(args) @@ -163,3 +416,31 @@ def create_exemption_category(): "is_active": 1, } ).insert() + + +def setup_hra_exemption_prerequisites(frequency): + from erpnext.payroll.doctype.salary_slip.test_salary_slip import create_tax_slab + from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure + + payroll_period = create_payroll_period(name="_Test Payroll Period 1", company="_Test Company") + + create_tax_slab( + payroll_period, + allow_tax_exemption=True, + currency="INR", + effective_date=getdate("2019-04-01"), + company="_Test Company", + ) + + make_salary_structure( + f"{frequency} Structure for HRA Exemption", + frequency, + employee=frappe.get_value("Employee", {"user_id": "employee@taxexepmtion.com"}, "name"), + company="_Test Company", + currency="INR", + payroll_period=payroll_period, + ) + + frappe.db.set_value( + "Company", "_Test Company", {"basic_component": "Basic Salary", "hra_component": "HRA"} + ) diff --git a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py index e9b5ed2261d..5c78e8f0375 100644 --- a/erpnext/payroll/doctype/salary_structure/test_salary_structure.py +++ b/erpnext/payroll/doctype/salary_structure/test_salary_structure.py @@ -230,9 +230,12 @@ def create_salary_structure_assignment( company=None, currency=erpnext.get_default_currency(), payroll_period=None, + base=None, + allow_duplicate=False, ): - - if frappe.db.exists("Salary Structure Assignment", {"employee": employee}): + if not allow_duplicate and frappe.db.exists( + "Salary Structure Assignment", {"employee": employee} + ): frappe.db.sql("""delete from `tabSalary Structure Assignment` where employee=%s""", (employee)) if not payroll_period: @@ -245,7 +248,7 @@ def create_salary_structure_assignment( salary_structure_assignment = frappe.new_doc("Salary Structure Assignment") salary_structure_assignment.employee = employee - salary_structure_assignment.base = 50000 + salary_structure_assignment.base = base or 50000 salary_structure_assignment.variable = 5000 if not from_date: