odoo/ext/custom-addons/hr_holidays_compute_days/models/hr_holidays.py

160 lines
6.0 KiB
Python

# Copyright 2017-2018 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import api, fields, models
from datetime import time
from dateutil import tz
class HrHolidays(models.Model):
_inherit = 'hr.holidays'
def _default_from_full_day(self):
"""Detect if we have select full day in calendar and return the
full day option accordingly.
"""
context = self.env.context
if context.get('default_date_from'):
dt = fields.Datetime.from_string(
context['default_date_from']
).replace(tzinfo=tz.gettz(self.env.user.tz)).astimezone(tz.tzutc())
return dt.hour == 5 and dt.minute == 0 and dt.second == 0
return False
def _default_to_full_day(self):
"""Detect if we have select full day in calendar and return the
full day option accordingly.
"""
context = self.env.context
if context.get('default_date_to'):
dt = fields.Datetime.from_string(
context['default_date_to']
).replace(tzinfo=tz.gettz(self.env.user.tz)).astimezone(tz.tzutc())
return dt.hour == 17 and dt.minute == 0 and dt.second == 0
return False
from_full_day = fields.Boolean(
default=lambda self: self._default_from_full_day(),
readonly=True,
copy=False,
states={
'draft': [('readonly', False)],
'confirm': [('readonly', False)]
},
)
to_full_day = fields.Boolean(
default=lambda self: self._default_to_full_day(),
readonly=True,
copy=False,
states={
'draft': [('readonly', False)],
'confirm': [('readonly', False)]
},
)
date_from_full = fields.Date(
compute="_compute_date_from_full",
inverse="_inverse_date_from_full",
readonly=True,
states={
'draft': [('readonly', False)],
'confirm': [('readonly', False)]
},
)
date_to_full = fields.Date(
compute="_compute_date_to_full",
inverse="_inverse_date_to_full",
readonly=True,
states={
'draft': [('readonly', False)],
'confirm': [('readonly', False)]
},
)
# Supporting field for avoiding limitation on storing readonly fields
number_of_days_temp_related = fields.Float(
related="number_of_days_temp", readonly=True,
)
@api.depends('date_from')
def _compute_date_from_full(self):
"""Put day in employee's user timezone, or user timezone as fallback"""
for record in self.filtered('date_from'):
tz_name = record.employee_id.user_id.tz or record.env.user.tz
dt = fields.Datetime.from_string(record.date_from).replace(
tzinfo=tz.tzutc(),
).astimezone(tz.gettz(tz_name)).date()
record.date_from_full = fields.Date.to_string(dt)
@api.depends('date_to')
def _compute_date_to_full(self):
"""Put day in employee's user timezone, or user timezone as fallback"""
for record in self.filtered('date_to'):
tz_name = record.employee_id.user_id.tz or record.env.user.tz
dt = fields.Datetime.from_string(record.date_to).replace(
tzinfo=tz.tzutc(),
).astimezone(tz.gettz(tz_name)).date()
record.date_to_full = fields.Date.to_string(dt)
def _inverse_date_from_full(self):
"""Put start of the day in employee's user timezone, or user timezone
as fallback.
"""
for record in self.filtered('from_full_day'):
tz_name = record.employee_id.user_id.tz or record.env.user.tz
dt = fields.Datetime.from_string(record.date_from_full).replace(
hour=0, minute=0, second=0, microsecond=0,
tzinfo=tz.gettz(tz_name),
).astimezone(tz.tzutc())
record.date_from = fields.Datetime.to_string(dt)
def _inverse_date_to_full(self):
"""Put end of the day in employee's user timezone, or user timezone
as fallback.
"""
for record in self.filtered('to_full_day'):
tz_name = record.employee_id.user_id.tz or record.env.user.tz
dt = fields.Datetime.from_string(record.date_to_full).replace(
hour=23, minute=59, second=59, microsecond=999999,
tzinfo=tz.gettz(tz_name),
).astimezone(tz.tzutc())
record.date_to = fields.Datetime.to_string(dt)
@api.onchange('date_from_full', 'from_full_day')
def _onchange_date_from_full(self):
"""As inverse methods only works on save, we have to add an onchange"""
self._inverse_date_from_full()
@api.onchange('date_to_full', 'to_full_day')
def _onchange_date_to_full(self):
"""As inverse methods only works on save, we have to add an onchange"""
self._inverse_date_to_full()
def _onchange_data_hr_holidays_compute_days(self):
"""Trigger the number of days computation also when you change the
employee or the leave type.
"""
self._onchange_date_to()
def _get_number_of_days(self, date_from, date_to, employee_id):
"""Pass context variable for including rest days or change passed dates
when computing full days.
"""
obj = self.with_context(
include_rest_days=not self.holiday_status_id.exclude_rest_days,
)
if self.holiday_status_id.compute_full_days:
dt_from = fields.Datetime.from_string(date_from)
date_from = fields.Datetime.to_string(
dt_from.combine(
dt_from.date(), time(hour=0, minute=0, second=0),
),
)
dt_to = fields.Datetime.from_string(date_to)
date_to = fields.Datetime.to_string(
dt_to.combine(
dt_to.date(), time(hour=23, minute=59, second=59),
),
)
return super(HrHolidays, obj)._get_number_of_days(
date_from, date_to, employee_id,
)