oca-ocb-hr/odoo-bringout-oca-ocb-hr/hr/models/resource.py
Ernad Husremovic e1d89e11e3 19.0 vanilla
2026-03-09 09:31:00 +01:00

137 lines
7 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from collections import defaultdict
from datetime import datetime
from pytz import timezone
from odoo import api, fields, models
from odoo.tools.intervals import Intervals
class ResourceResource(models.Model):
_inherit = "resource.resource"
user_id = fields.Many2one(copy=False)
employee_id = fields.One2many('hr.employee', 'resource_id', check_company=True, context={'active_test': False})
job_title = fields.Char(compute='_compute_job_title', compute_sudo=True)
department_id = fields.Many2one('hr.department', compute='_compute_department_id', compute_sudo=True)
work_location_id = fields.Many2one(related='employee_id.work_location_id')
work_email = fields.Char(related='employee_id.work_email')
work_phone = fields.Char(related='employee_id.work_phone')
show_hr_icon_display = fields.Boolean(related='employee_id.show_hr_icon_display')
hr_icon_display = fields.Selection(related='employee_id.hr_icon_display')
calendar_id = fields.Many2one(inverse='_inverse_calendar_id')
@api.depends('employee_id')
def _compute_job_title(self):
for resource in self:
resource.job_title = resource.employee_id.job_title
@api.depends('employee_id')
def _compute_department_id(self):
for resource in self:
resource.department_id = resource.employee_id.department_id
@api.depends('employee_id')
def _compute_avatar_128(self):
is_hr_user = self.env.user.has_group('hr.group_hr_user')
if not is_hr_user:
public_employees = self.env['hr.employee.public'].with_context(active_test=False).search([
('resource_id', 'in', self.ids),
])
avatar_per_employee_id = {emp.id: emp.avatar_128 for emp in public_employees}
for resource in self:
employee = resource.employee_id
if not employee:
resource.avatar_128 = False
continue
if is_hr_user:
resource.avatar_128 = employee[0].avatar_128
else:
resource.avatar_128 = avatar_per_employee_id[employee[0].id]
def _inverse_calendar_id(self):
for resource in self:
if resource.calendar_id != resource.employee_id.resource_calendar_id:
resource.employee_id.resource_calendar_id = resource.calendar_id
def _get_resource_without_contract(self):
employee_ids_with_active_contracts = {
employee.id for [employee] in
self.env['hr.version']._read_group(
domain=[
('employee_id', 'in', self.employee_id.ids),
('contract_date_start', '!=', False),
],
groupby=['employee_id'],
)
}
return self.filtered(
lambda r: not r.employee_id
or not r.employee_id.id in employee_ids_with_active_contracts
)
def _get_contracts_valid_periods(self, start, end):
res = defaultdict(lambda: defaultdict(Intervals))
timezones = {resource.tz for resource in self}
date_start = min(start.astimezone(timezone(tz)).date() for tz in timezones)
date_end = max(end.astimezone(timezone(tz)).date() for tz in timezones)
contracts = self.employee_id._get_versions_with_contract_overlap_with_period(date_start, date_end)
for contract in contracts:
tz = timezone(contract.employee_id.tz)
res[contract.employee_id.resource_id.id][contract.resource_calendar_id] |= Intervals([(
tz.localize(datetime.combine(contract.contract_date_start, datetime.min.time())) if contract.contract_date_start > start.astimezone(tz).date() else start,
tz.localize(datetime.combine(contract.contract_date_end, datetime.max.time())) if contract.contract_date_end and contract.contract_date_end < end.astimezone(tz).date() else end,
self.env['resource.calendar.attendance']
)])
return res
def _get_calendars_validity_within_period(self, start, end, default_company=None):
assert start.tzinfo and end.tzinfo
if not self:
return super()._get_calendars_validity_within_period(start, end, default_company=default_company)
calendars_within_period_per_resource = defaultdict(lambda: defaultdict(Intervals)) # keys are [resource id:integer][calendar:self.env['resource.calendar']]
# Employees that have ever had an active contract
resource_without_contract = self._get_resource_without_contract()
if resource_without_contract:
calendars_within_period_per_resource.update(
super(ResourceResource, resource_without_contract)._get_calendars_validity_within_period(start, end, default_company=default_company)
)
resource_with_contract = self - resource_without_contract
if not resource_with_contract:
return calendars_within_period_per_resource
calendars_within_period_per_resource.update(resource_with_contract._get_contracts_valid_periods(start, end))
return calendars_within_period_per_resource
def _get_flexible_resources_calendars_validity_within_period(self, start, end):
assert start.tzinfo and end.tzinfo
resource_default_work_intervals = self._get_flexible_resources_default_work_intervals(start, end)
calendars_within_period_per_resource = defaultdict(lambda: defaultdict(Intervals)) # keys are [resource id:integer][calendar:self.env['resource.calendar']]
# Employees that have ever had an active contract
resource_without_contract = self.sudo()._get_resource_without_contract()
for resource in resource_without_contract:
calendar = False if resource._is_fully_flexible() else resource.calendar_id
calendars_within_period_per_resource[resource.id][calendar] = resource_default_work_intervals[resource.id]
resource_with_contract = self - resource_without_contract
if resource_with_contract:
resource_contracts_valid_periods = resource_with_contract.sudo()._get_contracts_valid_periods(start, end)
# r: calendar: Intervals
for resource_id, calendar_intervals in resource_contracts_valid_periods.items():
for calendar_id, intervals in calendar_intervals.items():
calendars_within_period_per_resource[resource_id][calendar_id] = intervals & resource_default_work_intervals[resource_id]
return calendars_within_period_per_resource
def _get_calendar_at(self, date_target, tz=False):
result = super()._get_calendar_at(date_target)
resources_with_employee = self.filtered(lambda r: r.employee_id)
employee_calendars = resources_with_employee.employee_id._get_calendars(date_target.astimezone(tz))
for resource in resources_with_employee:
result[resource] = employee_calendars[resource.employee_id.id]
return result