-
Notifications
You must be signed in to change notification settings - Fork 7.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(Payroll): incorrect component amount calculation if dependent on …
…another payment days based component (#27349) * fix(Payroll): incorrect component amount calculation if dependent on another payment days based component * fix: set component amount precision at the end * fix: consider default amount during taxt calculations * test: component amount dependent on another payment days based component * fix: test
- Loading branch information
1 parent
7292f54
commit bab644a
Showing
2 changed files
with
167 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
getdate, | ||
nowdate, | ||
) | ||
from frappe.utils.make_random import get_random | ||
|
||
import erpnext | ||
from erpnext.accounts.utils import get_fiscal_year | ||
|
@@ -134,6 +135,65 @@ def test_payment_days_based_on_leave_application(self): | |
|
||
frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave") | ||
|
||
def test_component_amount_dependent_on_another_payment_days_based_component(self): | ||
from erpnext.hr.doctype.attendance.attendance import mark_attendance | ||
from erpnext.payroll.doctype.salary_structure.test_salary_structure import ( | ||
create_salary_structure_assignment, | ||
) | ||
|
||
no_of_days = self.get_no_of_days() | ||
# Payroll based on attendance | ||
frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Attendance") | ||
|
||
salary_structure = make_salary_structure_for_payment_days_based_component_dependency() | ||
employee = make_employee("[email protected]", company="_Test Company") | ||
|
||
# base = 50000 | ||
create_salary_structure_assignment(employee, salary_structure.name, company="_Test Company", currency="INR") | ||
|
||
# mark employee absent for a day since this case works fine if payment days are equal to working days | ||
month_start_date = get_first_day(nowdate()) | ||
month_end_date = get_last_day(nowdate()) | ||
|
||
first_sunday = frappe.db.sql(""" | ||
select holiday_date from `tabHoliday` | ||
where parent = 'Salary Slip Test Holiday List' | ||
and holiday_date between %s and %s | ||
order by holiday_date | ||
""", (month_start_date, month_end_date))[0][0] | ||
|
||
mark_attendance(employee, add_days(first_sunday, 1), 'Absent', ignore_validate=True) # counted as absent | ||
|
||
# make salary slip and assert payment days | ||
ss = make_salary_slip_for_payment_days_dependency_test("[email protected]", salary_structure.name) | ||
self.assertEqual(ss.absent_days, 1) | ||
|
||
days_in_month = no_of_days[0] | ||
no_of_holidays = no_of_days[1] | ||
|
||
self.assertEqual(ss.payment_days, days_in_month - no_of_holidays - 1) | ||
|
||
ss.reload() | ||
payment_days_based_comp_amount = 0 | ||
for component in ss.earnings: | ||
if component.salary_component == "HRA - Payment Days": | ||
payment_days_based_comp_amount = flt(component.amount, component.precision("amount")) | ||
break | ||
|
||
# check if the dependent component is calculated using the amount updated after payment days | ||
actual_amount = 0 | ||
precision = 0 | ||
for component in ss.deductions: | ||
if component.salary_component == "P - Employee Provident Fund": | ||
precision = component.precision("amount") | ||
actual_amount = flt(component.amount, precision) | ||
break | ||
|
||
expected_amount = flt((flt(ss.gross_pay) - payment_days_based_comp_amount) * 0.12, precision) | ||
|
||
self.assertEqual(actual_amount, expected_amount) | ||
frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave") | ||
|
||
def test_salary_slip_with_holidays_included(self): | ||
no_of_days = self.get_no_of_days() | ||
frappe.db.set_value("Payroll Settings", None, "include_holidays_in_total_working_days", 1) | ||
|
@@ -864,3 +924,91 @@ def make_holiday_list(): | |
holiday_list = holiday_list.name | ||
|
||
return holiday_list | ||
|
||
def make_salary_structure_for_payment_days_based_component_dependency(): | ||
earnings = [ | ||
{ | ||
"salary_component": "Basic Salary - Payment Days", | ||
"abbr": "P_BS", | ||
"type": "Earning", | ||
"formula": "base", | ||
"amount_based_on_formula": 1 | ||
}, | ||
{ | ||
"salary_component": "HRA - Payment Days", | ||
"abbr": "P_HRA", | ||
"type": "Earning", | ||
"depends_on_payment_days": 1, | ||
"amount_based_on_formula": 1, | ||
"formula": "base * 0.20" | ||
} | ||
] | ||
|
||
make_salary_component(earnings, False, company_list=["_Test Company"]) | ||
|
||
deductions = [ | ||
{ | ||
"salary_component": "P - Professional Tax", | ||
"abbr": "P_PT", | ||
"type": "Deduction", | ||
"depends_on_payment_days": 1, | ||
"amount": 200.00 | ||
}, | ||
{ | ||
"salary_component": "P - Employee Provident Fund", | ||
"abbr": "P_EPF", | ||
"type": "Deduction", | ||
"exempted_from_income_tax": 1, | ||
"amount_based_on_formula": 1, | ||
"depends_on_payment_days": 0, | ||
"formula": "(gross_pay - P_HRA) * 0.12" | ||
} | ||
] | ||
|
||
make_salary_component(deductions, False, company_list=["_Test Company"]) | ||
|
||
salary_structure = "Salary Structure with PF" | ||
if frappe.db.exists("Salary Structure", salary_structure): | ||
frappe.db.delete("Salary Structure", salary_structure) | ||
|
||
details = { | ||
"doctype": "Salary Structure", | ||
"name": salary_structure, | ||
"company": "_Test Company", | ||
"payroll_frequency": "Monthly", | ||
"payment_account": get_random("Account", filters={"account_currency": "INR"}), | ||
"currency": "INR" | ||
} | ||
|
||
salary_structure_doc = frappe.get_doc(details) | ||
|
||
for entry in earnings: | ||
salary_structure_doc.append("earnings", entry) | ||
|
||
for entry in deductions: | ||
salary_structure_doc.append("deductions", entry) | ||
|
||
salary_structure_doc.insert() | ||
salary_structure_doc.submit() | ||
|
||
return salary_structure_doc | ||
|
||
def make_salary_slip_for_payment_days_dependency_test(employee, salary_structure): | ||
employee = frappe.db.get_value("Employee", { | ||
"user_id": employee | ||
}, | ||
["name", "company", "employee_name"], | ||
as_dict=True) | ||
|
||
salary_slip_name = frappe.db.get_value("Salary Slip", {"employee": frappe.db.get_value("Employee", {"user_id": employee})}) | ||
|
||
if not salary_slip_name: | ||
salary_slip = make_salary_slip(salary_structure, employee=employee.name) | ||
salary_slip.employee_name = employee.employee_name | ||
salary_slip.payroll_frequency = "Monthly" | ||
salary_slip.posting_date = nowdate() | ||
salary_slip.insert() | ||
else: | ||
salary_slip = frappe.get_doc("Salary Slip", salary_slip_name) | ||
|
||
return salary_slip |