From 9ff1904aec13cfe147854e71a157fd72ae6db17c Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Wed, 30 Mar 2022 14:47:11 +0530 Subject: [PATCH] fix: explicitly check if additional salary is recurring while fetching components for payroll (#30489) --- .../additional_salary/additional_salary.py | 21 +++++- .../test_additional_salary.py | 65 +++++++++++++++---- 2 files changed, 71 insertions(+), 15 deletions(-) diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.py b/erpnext/payroll/doctype/additional_salary/additional_salary.py index 256a3b5530..18bd3b7733 100644 --- a/erpnext/payroll/doctype/additional_salary/additional_salary.py +++ b/erpnext/payroll/doctype/additional_salary/additional_salary.py @@ -147,6 +147,8 @@ class AdditionalSalary(Document): @frappe.whitelist() def get_additional_salaries(employee, start_date, end_date, component_type): + from frappe.query_builder import Criterion + comp_type = "Earning" if component_type == "earnings" else "Deduction" additional_sal = frappe.qb.DocType("Additional Salary") @@ -170,8 +172,23 @@ def get_additional_salaries(employee, start_date, end_date, component_type): & (additional_sal.type == comp_type) ) .where( - additional_sal.payroll_date[start_date:end_date] - | ((additional_sal.from_date <= end_date) & (additional_sal.to_date >= end_date)) + Criterion.any( + [ + Criterion.all( + [ # is recurring and additional salary dates fall within the payroll period + additional_sal.is_recurring == 1, + additional_sal.from_date <= end_date, + additional_sal.to_date >= end_date, + ] + ), + Criterion.all( + [ # is not recurring and additional salary's payroll date falls within the payroll period + additional_sal.is_recurring == 0, + additional_sal.payroll_date[start_date:end_date], + ] + ), + ] + ) ) .run(as_dict=True) ) diff --git a/erpnext/payroll/doctype/additional_salary/test_additional_salary.py b/erpnext/payroll/doctype/additional_salary/test_additional_salary.py index 7d5d9e02f3..bd739368a0 100644 --- a/erpnext/payroll/doctype/additional_salary/test_additional_salary.py +++ b/erpnext/payroll/doctype/additional_salary/test_additional_salary.py @@ -4,7 +4,8 @@ import unittest import frappe -from frappe.utils import add_days, nowdate +from frappe.tests.utils import FrappeTestCase +from frappe.utils import add_days, add_months, nowdate import erpnext from erpnext.hr.doctype.employee.test_employee import make_employee @@ -16,19 +17,10 @@ from erpnext.payroll.doctype.salary_slip.test_salary_slip import ( from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure -class TestAdditionalSalary(unittest.TestCase): +class TestAdditionalSalary(FrappeTestCase): def setUp(self): setup_test() - def tearDown(self): - for dt in [ - "Salary Slip", - "Additional Salary", - "Salary Structure Assignment", - "Salary Structure", - ]: - frappe.db.sql("delete from `tab%s`" % dt) - def test_recurring_additional_salary(self): amount = 0 salary_component = None @@ -46,19 +38,66 @@ class TestAdditionalSalary(unittest.TestCase): if earning.salary_component == "Recurring Salary Component": amount = earning.amount salary_component = earning.salary_component + break self.assertEqual(amount, add_sal.amount) self.assertEqual(salary_component, add_sal.salary_component) + def test_non_recurring_additional_salary(self): + amount = 0 + salary_component = None + date = nowdate() -def get_additional_salary(emp_id): + emp_id = make_employee("test_additional@salary.com") + frappe.db.set_value("Employee", emp_id, "relieving_date", add_days(date, 1800)) + salary_structure = make_salary_structure( + "Test Salary Structure Additional Salary", "Monthly", employee=emp_id + ) + add_sal = get_additional_salary(emp_id, recurring=False, payroll_date=date) + + ss = make_employee_salary_slip( + "test_additional@salary.com", "Monthly", salary_structure=salary_structure.name + ) + + amount, salary_component = None, None + for earning in ss.earnings: + if earning.salary_component == "Recurring Salary Component": + amount = earning.amount + salary_component = earning.salary_component + break + + self.assertEqual(amount, add_sal.amount) + self.assertEqual(salary_component, add_sal.salary_component) + + # should not show up in next months + ss.posting_date = add_months(date, 1) + ss.start_date = ss.end_date = None + ss.earnings = [] + ss.deductions = [] + ss.save() + + amount, salary_component = None, None + for earning in ss.earnings: + if earning.salary_component == "Recurring Salary Component": + amount = earning.amount + salary_component = earning.salary_component + break + + self.assertIsNone(amount) + self.assertIsNone(salary_component) + + +def get_additional_salary(emp_id, recurring=True, payroll_date=None): create_salary_component("Recurring Salary Component") add_sal = frappe.new_doc("Additional Salary") add_sal.employee = emp_id add_sal.salary_component = "Recurring Salary Component" - add_sal.is_recurring = 1 + + add_sal.is_recurring = 1 if recurring else 0 add_sal.from_date = add_days(nowdate(), -50) add_sal.to_date = add_days(nowdate(), 180) + add_sal.payroll_date = payroll_date + add_sal.amount = 5000 add_sal.currency = erpnext.get_default_currency() add_sal.save()