mirror of
https://github.com/bringout/oca-ocb-hr.git
synced 2026-04-21 21:51:58 +02:00
137 lines
7 KiB
Python
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
|