94 lines
4.1 KiB
Python
94 lines
4.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from collections import defaultdict
|
|
|
|
from dateutil import relativedelta
|
|
from pytz import timezone
|
|
|
|
from odoo import fields, models
|
|
|
|
|
|
class ResUsers(models.Model):
|
|
_inherit = 'res.users'
|
|
|
|
helpdesk_target_closed = fields.Integer(export_string_translation=False, default=1)
|
|
helpdesk_target_rating = fields.Float(export_string_translation=False, default=4.5)
|
|
helpdesk_target_success = fields.Float(export_string_translation=False, default=85)
|
|
|
|
_target_closed_not_zero = models.Constraint(
|
|
'CHECK(helpdesk_target_closed > 0)',
|
|
"You cannot have negative targets",
|
|
)
|
|
_target_rating_not_zero = models.Constraint(
|
|
'CHECK(helpdesk_target_rating > 0)',
|
|
"You cannot have negative targets",
|
|
)
|
|
_target_success_not_zero = models.Constraint(
|
|
'CHECK(helpdesk_target_success > 0)',
|
|
"You cannot have negative targets",
|
|
)
|
|
|
|
@property
|
|
def SELF_READABLE_FIELDS(self):
|
|
return super().SELF_READABLE_FIELDS + [
|
|
'helpdesk_target_closed',
|
|
'helpdesk_target_rating',
|
|
'helpdesk_target_success',
|
|
]
|
|
|
|
@property
|
|
def SELF_WRITEABLE_FIELDS(self):
|
|
return super().SELF_WRITEABLE_FIELDS + [
|
|
'helpdesk_target_closed',
|
|
'helpdesk_target_rating',
|
|
'helpdesk_target_success',
|
|
]
|
|
|
|
def _get_working_user_interval(self, start_dt, end_dt, calendar, compute_leaves=True):
|
|
# This method is intended to be overridden in hr_holidays in order to take non-validated leaves into account
|
|
return calendar._work_intervals_batch(
|
|
start_dt,
|
|
end_dt,
|
|
resources=self.resource_ids,
|
|
compute_leaves=compute_leaves
|
|
)
|
|
|
|
def _get_working_users_per_first_working_day(self):
|
|
"""
|
|
Given the users in self, determine which ones are available at the earliest moment.
|
|
This method only looks ahead up to one week from now.
|
|
|
|
:return: A list of list of user ids, in the order they are first available.
|
|
For instance, if your recordset contains users with ids 1, 2, 3 and 4, and:
|
|
- 1 and 3 are available today.
|
|
- 4 has a working schedule where they don't work today but will work tomorrow.
|
|
- 2 is on time off until two days from now.
|
|
The output of this method will be: [[1, 3], [4], [2]]
|
|
:rtype: List[List[int]]
|
|
"""
|
|
tz = timezone(self.env.context.get('tz') or 'UTC')
|
|
start_dt = fields.Datetime.now().astimezone(tz)
|
|
end_dt = start_dt + relativedelta.relativedelta(days=7, hour=23, minute=59, second=59)
|
|
workers_per_first_working_date = defaultdict(list)
|
|
users_per_calendar = defaultdict(lambda: self.env['res.users'])
|
|
company_calendar = self.env.company.resource_calendar_id
|
|
for user in self:
|
|
calendar = user.resource_ids.calendar_id[:1] or company_calendar
|
|
users_per_calendar[calendar] |= user
|
|
for calendar, users in users_per_calendar.items():
|
|
work_intervals_per_resource = users._get_working_user_interval(start_dt, end_dt, calendar)
|
|
for user in users:
|
|
for resource_id in user.resource_ids.ids:
|
|
intervals = work_intervals_per_resource[resource_id]
|
|
if intervals:
|
|
# select the start_date of the first interval to get the first working day for this user
|
|
workers_per_first_working_date[(intervals._items)[0][0].date()].append(user.id)
|
|
break
|
|
# if the user isn't linked to any employee then add according to company calendar
|
|
if user.id and not user.resource_ids:
|
|
intervals = work_intervals_per_resource[False]
|
|
if intervals:
|
|
workers_per_first_working_date[(intervals._items)[0][0].date()].append(user.id)
|
|
return [value for _key, value in sorted(workers_per_first_working_date.items())]
|