[FIX] hr_holidays: ignore unconfirmed leaves in current leave status

As of this commit, only confirmed leaves will be considered when computing the
current leave or absence of an employee. Additionally, a bug in the is_absent
search implementation was fixed: before this commit, the same results were
returned for absent and non-absent searches.

opw-2877328

closes odoo/odoo#124968

X-original-commit: 28ccbbab07a0c25570ca9b940428b8e541d262d7
Signed-off-by: Kevin Baptiste <kba@odoo.com>
This commit is contained in:
Tom De Caluwé
2023-06-14 13:10:49 +02:00
parent 233b964b99
commit 34f1bc96a2
5 changed files with 59 additions and 13 deletions
+8 -7
View File
@@ -5,6 +5,7 @@ import datetime
from dateutil.relativedelta import relativedelta
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.tools.float_utils import float_round
from odoo.addons.resource.models.utils import HOURS_PER_DAY
@@ -129,7 +130,7 @@ class HrEmployeeBase(models.AbstractModel):
('employee_id', 'in', self.ids),
('date_from', '<=', fields.Datetime.now()),
('date_to', '>=', fields.Datetime.now()),
('state', 'not in', ('cancel', 'refuse'))
('state', '=', 'validate'),
])
leave_data = {}
for holiday in holidays:
@@ -163,6 +164,8 @@ class HrEmployeeBase(models.AbstractModel):
employee.show_leaves = False
def _search_absent_employee(self, operator, value):
if operator not in ('=', '!=') or not isinstance(value, bool):
raise UserError(_('Operation not supported'))
# This search is only used for the 'Absent Today' filter however
# this only returns employees that are absent right now.
today_date = datetime.datetime.utcnow().date()
@@ -170,14 +173,12 @@ class HrEmployeeBase(models.AbstractModel):
today_end = fields.Datetime.to_string(today_date + relativedelta(hours=23, minutes=59, seconds=59))
holidays = self.env['hr.leave'].sudo().search([
('employee_id', '!=', False),
('state', 'not in', ['cancel', 'refuse']),
('state', '=', 'validate'),
('date_from', '<=', today_end),
('date_to', '>=', today_start),
])
op = 'not in'
if (operator == '=' and value) or (operator == '!=' and not value):
op = 'in'
return [('id', op, holidays.mapped('employee_id').ids)]
operator = ['in', 'not in'][(operator == '=') != value]
return [('id', operator, holidays.mapped('employee_id').ids)]
@api.model_create_multi
def create(self, vals_list):
@@ -242,7 +243,7 @@ class HrEmployee(models.Model):
('employee_id', 'in', self.ids),
('date_from', '<=', fields.Datetime.now()),
('date_to', '>=', fields.Datetime.now()),
('state', 'not in', ('cancel', 'refuse'))
('state', '=', 'validate'),
])
for holiday in holidays:
employee = self.filtered(lambda e: e.id == holiday.employee_id.id)
+1 -1
View File
@@ -51,7 +51,7 @@ class User(models.Model):
self.env['hr.leave'].flush_model(['user_id', 'state', 'date_from', 'date_to'])
self.env.cr.execute('''SELECT res_users.%s FROM res_users
JOIN hr_leave ON hr_leave.user_id = res_users.id
AND state in ('validate')
AND state = 'validate'
AND hr_leave.active = 't'
AND res_users.active = 't'
AND date_from <= %%s AND date_to >= %%s''' % field, (now, now))
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime, date
from datetime import datetime, date, timedelta
import time
from dateutil.relativedelta import relativedelta
from freezegun import freeze_time
@@ -1057,3 +1057,48 @@ class TestLeaveRequests(TestHrHolidaysCommon):
with self.assertRaises(ValidationError):
self.env['hr.leave'].with_user(self.user_employee_id).create(trigger_error_leave)
def test_current_leave_status(self):
types = ('no_validation', 'manager', 'hr', 'both')
employee = self.employee_emp
def run_validation_flow(leave_validation_type):
LeaveType = self.env['hr.leave.type'].with_user(self.user_hrmanager_id)
leave_type = LeaveType.with_context(tracking_disable=True).create({
'name': leave_validation_type.capitalize(),
'leave_validation_type': leave_validation_type,
'requires_allocation': 'no',
})
current_leave = self.env['hr.leave'].with_user(self.user_employee_id).create({
'name': 'Holiday Request',
'holiday_type': 'employee',
'employee_id': employee.id,
'holiday_status_id': leave_type.id,
'date_from': datetime.today() - timedelta(days=1),
'date_to': datetime.today() + timedelta(days=1),
})
if leave_validation_type in ('manager', 'both'):
self.assertFalse(employee.is_absent)
self.assertFalse(employee.current_leave_id)
self.assertEqual(employee.filtered_domain([('is_absent', '=', False)]), employee)
self.assertFalse(employee.filtered_domain([('is_absent', '=', True)]))
current_leave.with_user(self.user_hruser_id).action_approve()
if leave_validation_type in ('hr', 'both'):
self.assertFalse(employee.is_absent)
self.assertFalse(employee.current_leave_id)
self.assertEqual(employee.filtered_domain([('is_absent', '=', False)]), employee)
self.assertFalse(employee.filtered_domain([('is_absent', '=', True)]))
current_leave.with_user(self.user_hrmanager_id).action_validate()
self.assertTrue(employee.is_absent)
self.assertEqual(employee.current_leave_id, current_leave.holiday_status_id)
self.assertFalse(employee.filtered_domain([('is_absent', '=', False)]))
self.assertEqual(employee.filtered_domain([('is_absent', '=', True)]), employee)
raise RuntimeError()
for leave_validation_type in types:
with self.assertRaises(RuntimeError), self.env.cr.savepoint():
run_validation_flow(leave_validation_type)
@@ -105,12 +105,12 @@ class TestOutOfOfficePerformance(TestHrHolidaysCommon, TransactionCaseWithUserDe
self.assertEqual(self.hr_partner.im_status, 'leave_offline')
def test_search_absent_employee(self):
present_employees = self.env['hr.employee'].search([('is_absent', '!=', 'True')])
absent_employees = self.env['hr.employee'].search([('is_absent', '=', 'True')])
present_employees = self.env['hr.employee'].search([('is_absent', '!=', True)])
absent_employees = self.env['hr.employee'].search([('is_absent', '=', True)])
today_date = datetime.utcnow().date()
holidays = self.env['hr.leave'].sudo().search([
('employee_id', '!=', False),
('state', 'not in', ['cancel', 'refuse']),
('state', '=', 'validate'),
('date_from', '<=', today_date),
('date_to', '>=', today_date),
])
@@ -119,7 +119,7 @@ class ResourceCalendarLeaves(models.Model):
('employee_id', 'in', employee_ids_all),
('date_from', '<=', max_date),
('date_to', '>=', min_date),
('state', 'not in', ('cancel', 'refuse')),
('state', '=', 'validate'),
], ['employee_id'], ['date_from:array_agg', 'date_to:array_agg'])
holidays_by_employee = {
employee.id: [