From 938975d10f5d681dc22def9d9a678909a6879024 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 29 Aug 2024 13:47:30 +0530 Subject: [PATCH 1/2] fix: query for payroll cost centers should only consider the latest salary assignment --- .../doctype/payroll_entry/payroll_entry.py | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/hrms/payroll/doctype/payroll_entry/payroll_entry.py b/hrms/payroll/doctype/payroll_entry/payroll_entry.py index 7a22340d11..ad08acb272 100644 --- a/hrms/payroll/doctype/payroll_entry/payroll_entry.py +++ b/hrms/payroll/doctype/payroll_entry/payroll_entry.py @@ -470,18 +470,23 @@ def get_payroll_cost_centers_for_employee(self, employee, salary_structure): if not self.employee_cost_centers.get(employee): SalaryStructureAssignment = frappe.qb.DocType("Salary Structure Assignment") EmployeeCostCenter = frappe.qb.DocType("Employee Cost Center") - + assignment_subquery = ( + frappe.qb.from_(SalaryStructureAssignment) + .select(SalaryStructureAssignment.name) + .where( + (SalaryStructureAssignment.employee == employee) + & (SalaryStructureAssignment.salary_structure == salary_structure) + & (SalaryStructureAssignment.docstatus == 1) + & (SalaryStructureAssignment.from_date <= self.end_date) + ) + .orderby(SalaryStructureAssignment.from_date, order=frappe.qb.desc) + .limit(1) + ) cost_centers = dict( ( - frappe.qb.from_(SalaryStructureAssignment) - .join(EmployeeCostCenter) - .on(SalaryStructureAssignment.name == EmployeeCostCenter.parent) + frappe.qb.from_(EmployeeCostCenter) .select(EmployeeCostCenter.cost_center, EmployeeCostCenter.percentage) - .where( - (SalaryStructureAssignment.employee == employee) - & (SalaryStructureAssignment.docstatus == 1) - & (SalaryStructureAssignment.salary_structure == salary_structure) - ) + .where(EmployeeCostCenter.parent == assignment_subquery) ).run(as_list=True) ) From c036831d24c74e1464295270b5a980b144a0fc5f Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 29 Aug 2024 16:41:12 +0530 Subject: [PATCH 2/2] test: employee cost center breakup in payroll --- .../payroll_entry/test_payroll_entry.py | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/hrms/payroll/doctype/payroll_entry/test_payroll_entry.py b/hrms/payroll/doctype/payroll_entry/test_payroll_entry.py index 4a94e1b42f..6f148d2ce6 100644 --- a/hrms/payroll/doctype/payroll_entry/test_payroll_entry.py +++ b/hrms/payroll/doctype/payroll_entry/test_payroll_entry.py @@ -51,6 +51,7 @@ def setUp(self): "Payroll Entry", "Salary Structure", "Salary Structure Assignment", + "Employee Cost Center", "Payroll Employee Detail", "Additional Salary", ]: @@ -181,6 +182,57 @@ def test_payroll_entry_with_employee_cost_center(self): self.assertEqual(je_entries, expected_je) + @change_settings("Payroll Settings", {"process_payroll_accounting_entry_based_on_employee": 0}) + def test_employee_cost_center_breakup(self): + """Test only the latest salary structure assignment is considered for cost center breakup""" + COMPANY = "_Test Company" + COST_CENTERS = {"_Test Cost Center - _TC": 60, "_Test Cost Center 2 - _TC": 40} + department = create_department("Cost Center Test") + employee = make_employee("test_emp1@example.com", department=department, company=COMPANY) + salary_structure = make_salary_structure( + "_Test Salary Structure 2", + "Monthly", + employee, + company=COMPANY, + ) + + # update cost centers in salary structure assignment for employee + new_assignment = frappe.db.get_value( + "Salary Structure Assignment", + {"employee": employee, "salary_structure": salary_structure.name, "docstatus": 1}, + "name", + ) + new_assignment = frappe.get_doc("Salary Structure Assignment", new_assignment) + new_assignment.payroll_cost_centers = [] + for cost_center, percentage in COST_CENTERS.items(): + new_assignment.append( + "payroll_cost_centers", {"cost_center": cost_center, "percentage": percentage} + ) + new_assignment.save() + + # make an old salary structure assignment to test and ensure old cost center mapping is excluded + old_assignment = frappe.copy_doc(new_assignment) + old_assignment.from_date = add_months(new_assignment.from_date, -1) + old_assignment.payroll_cost_centers = [] + old_assignment.append("payroll_cost_centers", {"cost_center": "Main - _TC", "percentage": 100}) + old_assignment.submit() + + dates = get_start_end_dates("Monthly", nowdate()) + pe = make_payroll_entry( + start_date=dates.start_date, + end_date=dates.end_date, + payable_account="_Test Payroll Payable - _TC", + currency="INR", + department=department, + company="_Test Company", + payment_account="Cash - _TC", + cost_center="Main - _TC", + ) + + # only new cost center breakup is considered + cost_centers = pe.get_payroll_cost_centers_for_employee(employee, "_Test Salary Structure 2") + self.assertEqual(cost_centers, COST_CENTERS) + def test_get_end_date(self): self.assertEqual(get_end_date("2017-01-01", "monthly"), {"end_date": "2017-01-31"}) self.assertEqual(get_end_date("2017-02-01", "monthly"), {"end_date": "2017-02-28"})