[FIX] project_timesheet_holiday: only create GTO of employee's company
Followingfdb692c25b: - when creating/unarchiving an employee, we should only create global time-off of the same company as the employee itself - when computing the working hours relative to the GTO, if we had both calendar GTO and company GTO (not linked to a specific calendar), we were not correctly creating calendar GTO; we should merge those intervals intead of company GTO interval simply overwriting calendar GTO intervals closes odoo/odoo#145596 Task-id:3619083X-original-commit: 8ec0c6c106352c19e5c7b5613be2f610fa6e0adb Signed-off-by: Xavier Bol (xbo) <xbo@odoo.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
class Employee(models.Model):
|
||||
@@ -24,7 +25,8 @@ class Employee(models.Model):
|
||||
if 'active' in vals:
|
||||
if vals.get('active'):
|
||||
# Create future holiday timesheets
|
||||
self._create_future_public_holidays_timesheets(self)
|
||||
inactive_emp = self.filtered(lambda e: not e.active)
|
||||
inactive_emp._create_future_public_holidays_timesheets(self)
|
||||
else:
|
||||
# Delete future holiday timesheets
|
||||
self._delete_future_public_holidays_timesheets()
|
||||
@@ -42,12 +44,17 @@ class Employee(models.Model):
|
||||
def _create_future_public_holidays_timesheets(self, employees):
|
||||
lines_vals = []
|
||||
today = fields.Datetime.today()
|
||||
global_leaves_wo_calendar = self.env['resource.calendar.leaves'].search([('calendar_id', '=', False), ('date_from', '>=', today)])
|
||||
global_leaves_wo_calendar = defaultdict(lambda: self.env["resource.calendar.leaves"])
|
||||
global_leaves_wo_calendar.update(dict(self.env['resource.calendar.leaves']._read_group(
|
||||
[('calendar_id', '=', False), ('date_from', '>=', today)],
|
||||
groupby=['company_id'],
|
||||
aggregates=['id:recordset'],
|
||||
)))
|
||||
for employee in employees:
|
||||
if not employee.active:
|
||||
continue
|
||||
# First we look for the global time off that are already planned after today
|
||||
global_leaves = employee.resource_calendar_id.global_leave_ids.filtered(lambda l: l.date_from >= today) + global_leaves_wo_calendar
|
||||
global_leaves = employee.resource_calendar_id.global_leave_ids.filtered(lambda l: l.date_from >= today) + global_leaves_wo_calendar[employee.company_id]
|
||||
work_hours_data = global_leaves._work_time_per_day()
|
||||
for global_time_off in global_leaves:
|
||||
for index, (day_date, work_hours_count) in enumerate(work_hours_data[employee.resource_calendar_id.id][global_time_off.id]):
|
||||
|
||||
@@ -28,7 +28,7 @@ class ResourceCalendarLeaves(models.Model):
|
||||
(b) the resources which have a leave,
|
||||
(c) the oldest and
|
||||
(d) the latest leave dates
|
||||
) for leaves in self.
|
||||
) for leaves in self (first for calendar's leaves, then for company's global leaves)
|
||||
2) Search the attendances based on the characteristics retrieved for each calendar.
|
||||
The attendances found are the ones between the date_from of the oldest leave
|
||||
and the date_to of the most recent leave.
|
||||
@@ -41,8 +41,11 @@ class ResourceCalendarLeaves(models.Model):
|
||||
}
|
||||
"""
|
||||
resource_calendars = resource_calendars or self._get_resource_calendars()
|
||||
# to easily find the calendar with its id.
|
||||
calendars_dict = {calendar.id: calendar for calendar in resource_calendars}
|
||||
|
||||
leaves_read_group = self.env['resource.calendar.leaves']._read_group(
|
||||
[('id', 'in', self.ids)],
|
||||
[('id', 'in', self.ids), ('calendar_id', '!=', False)],
|
||||
['calendar_id'],
|
||||
['id:recordset', 'resource_id:recordset', 'date_from:min', 'date_to:max'],
|
||||
)
|
||||
@@ -56,13 +59,33 @@ class ResourceCalendarLeaves(models.Model):
|
||||
'resources': resources,
|
||||
'leaves': leaves,
|
||||
}
|
||||
if not calendar:
|
||||
for calendar_id in resource_calendars.ids:
|
||||
cal_attendance_intervals_dict[calendar.id] = calendar_data
|
||||
|
||||
comp_leaves_read_group = self.env['resource.calendar.leaves']._read_group(
|
||||
[('id', 'in', self.ids), ('calendar_id', '=', False)],
|
||||
['company_id'],
|
||||
['id:recordset', 'resource_id:recordset', 'date_from:min', 'date_to:max'],
|
||||
)
|
||||
for company, leaves, resources, date_from_min, date_to_max in comp_leaves_read_group:
|
||||
for calendar_id in resource_calendars.ids:
|
||||
if calendars_dict[calendar_id].company_id != company:
|
||||
continue # only consider global leaves of the same company as the calendar
|
||||
calendar_data = cal_attendance_intervals_dict.get(calendar_id)
|
||||
if calendar_data is None:
|
||||
calendar_data = {
|
||||
'date_from': utc.localize(date_from_min),
|
||||
'date_to': utc.localize(date_to_max),
|
||||
'resources': resources,
|
||||
'leaves': leaves,
|
||||
}
|
||||
cal_attendance_intervals_dict[calendar_id] = calendar_data
|
||||
else:
|
||||
cal_attendance_intervals_dict[calendar.id] = calendar_data
|
||||
# to easily find the calendar with its id.
|
||||
calendars_dict = {calendar.id: calendar for calendar in resource_calendars}
|
||||
else:
|
||||
calendar_data.update(
|
||||
date_from=min(utc.localize(date_from_min), calendar_data['date_from']),
|
||||
date_to=max(utc.localize(date_to_max), calendar_data['date_to']),
|
||||
resources=resources | calendar_data['resources'],
|
||||
leaves=leaves | calendar_data['leaves'],
|
||||
)
|
||||
|
||||
# dict of keys: calendar_id
|
||||
# and values: a dict of keys: leave.id
|
||||
|
||||
@@ -68,6 +68,11 @@ class TestTimesheetGlobalTimeOff(common.TransactionCase):
|
||||
},
|
||||
])
|
||||
|
||||
# Create a 2nd company
|
||||
self.test_company_2 = self.env['res.company'].create({
|
||||
'name': 'My Test Company 2',
|
||||
})
|
||||
|
||||
def _get_timesheets_by_employee(self, leave_task):
|
||||
timesheets_by_read_dict = self.env['account.analytic.line']._read_group([('task_id', '=', leave_task.id)], ['employee_id'], ['__count'])
|
||||
return {
|
||||
@@ -121,19 +126,38 @@ class TestTimesheetGlobalTimeOff(common.TransactionCase):
|
||||
'date_to': leave_end_datetime,
|
||||
})
|
||||
|
||||
# 5 Timesheets should have been created for full_time_employee
|
||||
# Create a global time-off in the same company (not specific a to calendar)
|
||||
# this should be added to calendar's leaves
|
||||
self.env['resource.calendar.leaves'].with_company(self.test_company).create({
|
||||
'name': 'Global leave',
|
||||
'calendar_id': False,
|
||||
'date_from': (leave_start_datetime + timedelta(weeks=1)).replace(hour=0, minute=0, second=0),
|
||||
'date_to': (leave_start_datetime + timedelta(weeks=1, days=1)).replace(hour=23, minute=59, second=59),
|
||||
})
|
||||
|
||||
# Create a global time-off in another company which should not be
|
||||
# taken into account when creating/unarchiving employee
|
||||
self.env['resource.calendar.leaves'].with_company(self.test_company_2).create({
|
||||
'name': 'Global leave in another company',
|
||||
'calendar_id': False,
|
||||
# Monday in two weeks
|
||||
'date_from': (leave_start_datetime + timedelta(weeks=2)).replace(hour=0, minute=0, second=0),
|
||||
'date_to': (leave_start_datetime + timedelta(weeks=2)).replace(hour=23, minute=59, second=59),
|
||||
})
|
||||
|
||||
# 7 Timesheets should have been created for full_time_employee
|
||||
timesheets_full_time_employee = self.env['account.analytic.line'].search([('employee_id', '=', self.full_time_employee.id)])
|
||||
self.assertEqual(len(timesheets_full_time_employee), 5)
|
||||
self.assertEqual(len(timesheets_full_time_employee), 7)
|
||||
|
||||
# All timesheets should have been deleted for full_time_employee when he is archived
|
||||
self.full_time_employee.active = False
|
||||
timesheets_full_time_employee = self.env['account.analytic.line'].search([('employee_id', '=', self.full_time_employee.id)])
|
||||
self.assertEqual(len(timesheets_full_time_employee), 0)
|
||||
|
||||
# 5 Timesheets should have been created for full_time_employee when he is unarchived
|
||||
# 7 Timesheets should have been created for full_time_employee when he is unarchived
|
||||
self.full_time_employee.active = True
|
||||
timesheets_full_time_employee = self.env['account.analytic.line'].search([('employee_id', '=', self.full_time_employee.id)])
|
||||
self.assertEqual(len(timesheets_full_time_employee), 5)
|
||||
self.assertEqual(len(timesheets_full_time_employee), 7)
|
||||
|
||||
# This tests that no timesheet are created for days when the employee is not supposed to work
|
||||
def test_no_timesheet_on_off_days(self):
|
||||
|
||||
Reference in New Issue
Block a user