From 1df01723583975a33204634c3c23aa686bbba58b Mon Sep 17 00:00:00 2001 From: hkafe-odoo Date: Tue, 4 Nov 2025 17:01:15 +0100 Subject: [PATCH] [FIX] hr_holidays: fix search on leave type **Steps to reproduce:** Navigate to Time Off >> Configuration >> Time Off Types >> Open any type, navigate to the Smart button Time Off >> Click on New >> Time Off Type Leads to an error. Reference Video: https://drive.google.com/file/d/1vi_apL24Km5tSomQtwcTArqqWvrBR5ni/view?usp=drive_link **Reason:** The `op` function is a comparison operator function that expects two values to compare and we are only passing to it `leave_type.virtual_remaining_leaves` parameter. **Solution:** Added the missing `value` parameter. Task: 5238200 --- addons/hr_holidays/models/hr_leave_type.py | 2 +- .../hr_holidays/tests/test_hr_leave_type.py | 72 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/addons/hr_holidays/models/hr_leave_type.py b/addons/hr_holidays/models/hr_leave_type.py index 8cedee4bed916..f93d621cc8a73 100644 --- a/addons/hr_holidays/models/hr_leave_type.py +++ b/addons/hr_holidays/models/hr_leave_type.py @@ -280,7 +280,7 @@ def _search_virtual_remaining_leaves(self, operator, value): leave_types = self.env['hr.leave.type'].search([]) def is_valid(leave_type): - return not leave_type.requires_allocation or op(leave_type.virtual_remaining_leaves) + return not leave_type.requires_allocation or op(leave_type.virtual_remaining_leaves, value) return [('id', 'in', leave_types.filtered(is_valid).ids)] @api.depends_context('employee_id', 'default_employee_id', 'leave_date_from', 'default_date_from') diff --git a/addons/hr_holidays/tests/test_hr_leave_type.py b/addons/hr_holidays/tests/test_hr_leave_type.py index b7732013987c5..b672d449b2d75 100644 --- a/addons/hr_holidays/tests/test_hr_leave_type.py +++ b/addons/hr_holidays/tests/test_hr_leave_type.py @@ -114,3 +114,75 @@ def test_users_tz_shift_back(self): ).search([('has_valid_allocation', '=', True)], limit=1) self.assertFalse(leave_types, "Got valid leaves outside vaild period") + + def test_search_virtual_remaining_leaves(self): + employee = self.env['hr.employee'].create({'name': 'Test Employee'}) + leave_type_1 = self.env['hr.leave.type'].create({ + 'name': 'Test Leave 1', + 'requires_allocation': True, + }) + leave_type_2 = self.env['hr.leave.type'].create({ + 'name': 'Test Leave 2', + 'requires_allocation': False, + }) + + self.env['hr.leave.allocation'].sudo().create({ + 'state': 'confirm', + 'holiday_status_id': leave_type_1.id, + 'employee_id': employee.id, + 'number_of_days': 4, + 'date_from': '2025-01-01', + 'date_to': '2025-12-31', + }).action_approve() + + test_cases = [ + # (operator, value, expected_leave_type_1, expected_leave_type_2, description_type_1, description_type_2) + ( + ">", + 0, + True, + True, + "should be in the result as it has remaining leaves", + "should be in the result since it does not require allocation", + ), + ( + "=", + 0, + False, + True, + "should not be in the result as it has remaining leaves != 0", + "should be in the result since it does not require allocation", + ), + ( + ">", + 4, + False, + True, + "should not be in the result", + "should be in the result since it does not require allocation", + ), + ] + + for ( + operator, + value, + expected_type_1, + expected_type_2, + description_type_1, + description_type_2, + ) in test_cases: + result = ( + self.env["hr.leave.type"] + .with_context(employee_id=employee.id) + .search([("virtual_remaining_leaves", operator, value)]) + ) + self.assertIn( + leave_type_1, result, f"Leave Type 1 {description_type_1}", + ) if expected_type_1 else self.assertNotIn( + leave_type_1, result, f"Leave Type 1 {description_type_1}", + ) + self.assertIn( + leave_type_2, result, f"Leave Type 2 {description_type_2}", + ) if expected_type_2 else self.assertNotIn( + leave_type_2, result, f"Leave Type 2 {description_type_2}", + )