From 2fac99df359b46c85eef583e08f86d470eed5c11 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 2 Jan 2025 16:54:16 +0530 Subject: [PATCH 1/9] fix(CTC): `amount_exempted_from_income_tax` only considers last deduction item (exempted from IT), not all (backport #2568) (#2570) Co-authored-by: Rucha Mahabal --- hrms/payroll/doctype/salary_slip/salary_slip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrms/payroll/doctype/salary_slip/salary_slip.py b/hrms/payroll/doctype/salary_slip/salary_slip.py index a72b568b40..b07c906aba 100644 --- a/hrms/payroll/doctype/salary_slip/salary_slip.py +++ b/hrms/payroll/doctype/salary_slip/salary_slip.py @@ -1678,7 +1678,7 @@ def get_taxable_earnings(self, allow_tax_exemption=False, based_on_payment_days= taxable_earnings -= flt(amount - additional_amount) additional_income -= additional_amount - amount_exempted_from_income_tax = flt(amount - additional_amount) + amount_exempted_from_income_tax += flt(amount - additional_amount) if additional_amount and ded.is_recurring_additional_salary: additional_income -= self.get_future_recurring_additional_amount( From bc4436b6d9138df4aacace501936fafae818ea13 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 2 Jan 2025 17:47:20 +0530 Subject: [PATCH 2/9] fix: skip patch if previous doctype doesn't exist (backport #2571) (#2572) Co-authored-by: Raffael Meyer <14891507+barredterra@users.noreply.github.com> --- .../migrate_shift_assignment_schedule_to_shift_schedule.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hrms/patches/v15_0/migrate_shift_assignment_schedule_to_shift_schedule.py b/hrms/patches/v15_0/migrate_shift_assignment_schedule_to_shift_schedule.py index fe94689a06..94b09c8997 100644 --- a/hrms/patches/v15_0/migrate_shift_assignment_schedule_to_shift_schedule.py +++ b/hrms/patches/v15_0/migrate_shift_assignment_schedule_to_shift_schedule.py @@ -4,6 +4,9 @@ def execute(): + if not frappe.db.has_table("Shift Assignment Schedule"): + return + fields = ["name", "shift_type", "frequency", "employee", "shift_status", "enabled", "create_shifts_after"] for doc in frappe.get_all("Shift Assignment Schedule", fields=fields): repeat_on_days = frappe.get_all( From 8e9882d038cfc767d384bdb3be793644a5ca36d7 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 2 Jan 2025 18:00:04 +0530 Subject: [PATCH 3/9] fix: correct date handling for get_weekday in shift schedule assignment (backport #2567) (#2573) Co-authored-by: UmakanthKaspa --- .../shift_schedule_assignment/shift_schedule_assignment.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hrms/hr/doctype/shift_schedule_assignment/shift_schedule_assignment.py b/hrms/hr/doctype/shift_schedule_assignment/shift_schedule_assignment.py index 430c1fdc82..24a405fe3f 100644 --- a/hrms/hr/doctype/shift_schedule_assignment/shift_schedule_assignment.py +++ b/hrms/hr/doctype/shift_schedule_assignment/shift_schedule_assignment.py @@ -3,7 +3,7 @@ import frappe from frappe.model.document import Document -from frappe.utils import add_days, get_weekday, nowdate +from frappe.utils import add_days, get_weekday, getdate, nowdate from hrms.hr.doctype.shift_assignment_tool.shift_assignment_tool import create_shift_assignment @@ -20,14 +20,14 @@ def create_shifts(self, start_date: str, end_date: str | None = None) -> None: date = start_date individual_assignment_start = None - week_end_day = get_weekday(add_days(start_date, -1)) + week_end_day = get_weekday(getdate(add_days(start_date, -1))) repeat_on_days = [day.day for day in shift_schedule.repeat_on_days] if not end_date: end_date = add_days(start_date, 90) while date <= end_date: - weekday = get_weekday(date) + weekday = get_weekday(getdate(date)) if weekday in repeat_on_days: if not individual_assignment_start: individual_assignment_start = date From ef156692209b6ff317799f9fd9b565ca247df999 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Mon, 6 Jan 2025 23:02:46 +0530 Subject: [PATCH 4/9] test(fix): create missing test fixtures (cherry picked from commit 811f13d3b9e2a76df11623b830342e0868332b3e) --- hrms/hr/report/leave_ledger/test_leave_ledger.py | 1 + hrms/payroll/doctype/salary_slip/test_salary_slip.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/hrms/hr/report/leave_ledger/test_leave_ledger.py b/hrms/hr/report/leave_ledger/test_leave_ledger.py index 160f42699c..bad2fb7e83 100644 --- a/hrms/hr/report/leave_ledger/test_leave_ledger.py +++ b/hrms/hr/report/leave_ledger/test_leave_ledger.py @@ -48,6 +48,7 @@ def setUp(self): # create leave type self.earned_leave = "Test Earned Leave" self.casual_leave = "_Test Leave Type" + create_leave_type(leave_type=self.casual_leave) self.create_earned_leave_allocation() self.create_casual_leave_allocation() diff --git a/hrms/payroll/doctype/salary_slip/test_salary_slip.py b/hrms/payroll/doctype/salary_slip/test_salary_slip.py index 316838c56e..17e0fcb743 100644 --- a/hrms/payroll/doctype/salary_slip/test_salary_slip.py +++ b/hrms/payroll/doctype/salary_slip/test_salary_slip.py @@ -5,6 +5,7 @@ import random import frappe +from frappe.core.doctype.user_permission.test_user_permission import create_user from frappe.model.document import Document from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import ( @@ -2168,6 +2169,8 @@ def make_leave_application( half_day_date=None, submit=True, ): + create_user("test@example.com") + leave_application = frappe.get_doc( dict( doctype="Leave Application", From d069cf9848e4ed7cecb4a35129400b1542b21d75 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Mon, 6 Jan 2025 23:26:01 +0530 Subject: [PATCH 5/9] test(fix): Leave Ledger - skip weekly offs in test holiday list for deterministic results - weekly off dates will vary every year, testing against dynamic holiday list isn't necessary for leave ledger (cherry picked from commit d2920e855262f277251e403a1bb86e618005e91c) --- hrms/hr/report/leave_ledger/test_leave_ledger.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/hrms/hr/report/leave_ledger/test_leave_ledger.py b/hrms/hr/report/leave_ledger/test_leave_ledger.py index bad2fb7e83..01bf27d706 100644 --- a/hrms/hr/report/leave_ledger/test_leave_ledger.py +++ b/hrms/hr/report/leave_ledger/test_leave_ledger.py @@ -33,16 +33,19 @@ def setUp(self): self.year_start = getdate(get_year_start(self.date)) self.year_end = getdate(get_year_ending(self.date)) - self.holiday_list = make_holiday_list( - "_Test Emp Balance Holiday List", self.year_start, self.year_end + holiday_list = make_holiday_list( + "_Test Emp Balance Holiday List", + self.year_start, + self.year_end, + add_weekly_offs=False, ) - - # create employee 1 & 2 self.employee_1 = frappe.get_doc( - "Employee", make_employee("test_emp_1@example.com", company="_Test Company") + "Employee", + make_employee("test_emp_1@example.com", company="_Test Company", holiday_list=holiday_list), ) self.employee_2 = frappe.get_doc( - "Employee", make_employee("test_emp_2@example.com", company="_Test Company") + "Employee", + make_employee("test_emp_2@example.com", company="_Test Company", holiday_list=holiday_list), ) # create leave type From 0d12e0c4d649032178c97be6935e7100bffcb5b4 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Mon, 6 Jan 2025 23:56:40 +0530 Subject: [PATCH 6/9] test(fix): set correct holiday list - tests generate holiday list as per current year. Those who assert against hardcoded dates from previous years fail as holidays from prev year aren't applicable anymore - set that year's holiday list for tests that check against exact dates (cherry picked from commit e26b49d9542e6d9445c9c1f8fdd77426f79315c8) --- hrms/hr/report/leave_ledger/test_leave_ledger.py | 1 + hrms/payroll/doctype/salary_slip/test_salary_slip.py | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/hrms/hr/report/leave_ledger/test_leave_ledger.py b/hrms/hr/report/leave_ledger/test_leave_ledger.py index 01bf27d706..ce758de163 100644 --- a/hrms/hr/report/leave_ledger/test_leave_ledger.py +++ b/hrms/hr/report/leave_ledger/test_leave_ledger.py @@ -51,6 +51,7 @@ def setUp(self): # create leave type self.earned_leave = "Test Earned Leave" self.casual_leave = "_Test Leave Type" + create_leave_type(leave_type=self.earned_leave) create_leave_type(leave_type=self.casual_leave) self.create_earned_leave_allocation() diff --git a/hrms/payroll/doctype/salary_slip/test_salary_slip.py b/hrms/payroll/doctype/salary_slip/test_salary_slip.py index 17e0fcb743..e5d08272a3 100644 --- a/hrms/payroll/doctype/salary_slip/test_salary_slip.py +++ b/hrms/payroll/doctype/salary_slip/test_salary_slip.py @@ -372,8 +372,16 @@ def test_payment_days_based_on_leave_application(self): self.assertEqual(ss.payment_days, days_in_month - no_of_holidays - 3.75) @change_settings("Payroll Settings", {"payroll_based_on": "Leave"}) - def test_payment_days_calculation_for_varying_leave_ranges(self): - emp_id = make_employee("test_payment_days_based_on_leave_application@salary.com") + def test_payment_days_calculation_for_lwp_on_month_boundaries(self): + """Tests LWP calculation leave applications created on month boundaries""" + holiday_list = make_holiday_list( + "Test Holiday List", + "2024-01-01", + "2024-12-31", + ) + emp_id = make_employee( + "test_payment_days_based_on_leave_application@salary.com", holiday_list=holiday_list + ) make_leave_application(emp_id, "2024-06-28", "2024-07-03", "Leave Without Pay") # 3 days in July make_leave_application(emp_id, "2024-07-10", "2024-07-13", "Leave Without Pay") # 4 days in July From 9640c73c46feca1f1c41d1af9426dc426d589f27 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 7 Jan 2025 00:52:55 +0530 Subject: [PATCH 7/9] test(refactor): use consistent dates in all salary withholding tests - currently 1 test uses hardcoded dates from 2024, while others use dynamic dates from current year, leading to missing salary structure assignment validations - use the same dates in all tests, no need to test this against dynamic data (cherry picked from commit 689e9d837fa675e8a148da5de08b67120f5b7ed8) # Conflicts: # hrms/payroll/doctype/salary_withholding/test_salary_withholding.py --- .../test_salary_withholding.py | 57 ++++++++++++------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/hrms/payroll/doctype/salary_withholding/test_salary_withholding.py b/hrms/payroll/doctype/salary_withholding/test_salary_withholding.py index 5d4ad486cb..e08a6b64e9 100644 --- a/hrms/payroll/doctype/salary_withholding/test_salary_withholding.py +++ b/hrms/payroll/doctype/salary_withholding/test_salary_withholding.py @@ -2,8 +2,13 @@ # See license.txt import frappe +<<<<<<< HEAD from frappe.tests.utils import FrappeTestCase from frappe.utils import get_first_day, get_year_start, getdate +======= +from frappe.tests import IntegrationTestCase +from frappe.utils import getdate +>>>>>>> 689e9d83 (test(refactor): use consistent dates in all salary withholding tests) from erpnext.setup.doctype.employee.test_employee import make_employee @@ -11,6 +16,12 @@ from hrms.payroll.doctype.payroll_entry.test_payroll_entry import make_payroll_entry from hrms.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure +COMPANY_NAME = "_Test Company" +MONTH_1_START = getdate("2024-01-01") +MONTH_1_END = getdate("2024-01-31") +MONTH_2_START = getdate("2024-02-01") +MONTH_2_END = getdate("2024-02-29") + class TestSalaryWithholding(FrappeTestCase): def setUp(self): @@ -26,28 +37,36 @@ def setUp(self): ]: frappe.db.delete(dt) - self.company = frappe.get_doc("Company", "_Test Company") - self.employee1 = make_employee("employee1@example.com", company=self.company, designation="Engineer") - self.employee2 = make_employee("employee2@example.com", company=self.company, designation="Engineer") + self.company = frappe.get_doc("Company", COMPANY_NAME) + self.employee1 = make_employee("employee1@example.com", company=COMPANY_NAME, designation="Engineer") + self.employee2 = make_employee("employee2@example.com", company=COMPANY_NAME, designation="Engineer") - self.today = getdate() - year_start = get_year_start(self.today) - make_salary_structure("Test Withholding", "Monthly", employee=self.employee1, from_date=year_start) - make_salary_structure("Test Withholding", "Monthly", employee=self.employee2, from_date=year_start) + make_salary_structure( + "Test Withholding", + "Monthly", + company=COMPANY_NAME, + employee=self.employee1, + from_date=MONTH_1_START, + ) + make_salary_structure( + "Test Withholding", + "Monthly", + company=COMPANY_NAME, + employee=self.employee2, + from_date=MONTH_1_START, + ) def test_set_withholding_cycles_and_to_date(self): - from_date = getdate("2024-06-01") - to_date = getdate("2024-07-31") - withholding = create_salary_withholding(self.employee1, from_date, 2) + withholding = create_salary_withholding(self.employee1, MONTH_1_START, 2) - self.assertEqual(withholding.to_date, to_date) - self.assertEqual(withholding.cycles[0].from_date, from_date) - self.assertEqual(withholding.cycles[0].to_date, getdate("2024-06-30")) - self.assertEqual(withholding.cycles[1].from_date, getdate("2024-07-01")) - self.assertEqual(withholding.cycles[1].to_date, to_date) + self.assertEqual(withholding.to_date, MONTH_2_END) + self.assertEqual(withholding.cycles[0].from_date, MONTH_1_START) + self.assertEqual(withholding.cycles[0].to_date, MONTH_1_END) + self.assertEqual(withholding.cycles[1].from_date, MONTH_2_START) + self.assertEqual(withholding.cycles[1].to_date, MONTH_2_END) def test_salary_withholding(self): - withholding = create_salary_withholding(self.employee1, get_first_day(self.today), 2) + withholding = create_salary_withholding(self.employee1, MONTH_1_START, 2) withholding.submit() payroll_entry = self._make_payroll_entry() @@ -61,7 +80,7 @@ def test_salary_withholding(self): self.assertEqual(withholding.status, "Withheld") def test_release_withheld_salaries(self): - withholding = create_salary_withholding(self.employee1, get_first_day(self.today), 2) + withholding = create_salary_withholding(self.employee1, MONTH_1_START, 2) withholding.submit() def test_run_payroll_for_cycle(withholding_cycle): @@ -106,7 +125,7 @@ def test_run_payroll_for_cycle(withholding_cycle): self.assertEqual(payroll_employee.is_salary_withheld, 1) def _make_payroll_entry(self, date: str | None = None): - dates = get_start_end_dates("Monthly", date or self.today) + dates = get_start_end_dates("Monthly", date or MONTH_1_START) return make_payroll_entry( start_date=dates.start_date, end_date=dates.end_date, @@ -117,7 +136,7 @@ def _make_payroll_entry(self, date: str | None = None): def _submit_bank_entry(self, bank_entry: dict): bank_entry.cheque_no = "123456" - bank_entry.cheque_date = self.today + bank_entry.cheque_date = MONTH_1_START bank_entry.submit() def _get_payroll_employee_row(self, payroll_entry: dict) -> dict | None: From aecb8712ed04d5ac8a4f05d5852b2083e8107542 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 7 Jan 2025 01:10:43 +0530 Subject: [PATCH 8/9] chore: fix conflicts --- .../doctype/salary_withholding/test_salary_withholding.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hrms/payroll/doctype/salary_withholding/test_salary_withholding.py b/hrms/payroll/doctype/salary_withholding/test_salary_withholding.py index e08a6b64e9..cde3fd0fda 100644 --- a/hrms/payroll/doctype/salary_withholding/test_salary_withholding.py +++ b/hrms/payroll/doctype/salary_withholding/test_salary_withholding.py @@ -2,13 +2,8 @@ # See license.txt import frappe -<<<<<<< HEAD -from frappe.tests.utils import FrappeTestCase -from frappe.utils import get_first_day, get_year_start, getdate -======= -from frappe.tests import IntegrationTestCase +from frappe.tests import FrappeTestCase from frappe.utils import getdate ->>>>>>> 689e9d83 (test(refactor): use consistent dates in all salary withholding tests) from erpnext.setup.doctype.employee.test_employee import make_employee From 81620c08383ff6831d6d56278960ca53a7cb1686 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Tue, 7 Jan 2025 01:11:35 +0530 Subject: [PATCH 9/9] chore: fix conflicts --- .../doctype/salary_withholding/test_salary_withholding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrms/payroll/doctype/salary_withholding/test_salary_withholding.py b/hrms/payroll/doctype/salary_withholding/test_salary_withholding.py index cde3fd0fda..5910c35601 100644 --- a/hrms/payroll/doctype/salary_withholding/test_salary_withholding.py +++ b/hrms/payroll/doctype/salary_withholding/test_salary_withholding.py @@ -2,7 +2,7 @@ # See license.txt import frappe -from frappe.tests import FrappeTestCase +from frappe.tests.utils import FrappeTestCase from frappe.utils import getdate from erpnext.setup.doctype.employee.test_employee import make_employee