Files
odoo_source/addons/resource/models/resource_calendar_leaves.py
T
vevi-odoo 1d1dcefc06 [FIX] resource: prevent traceback with false start date
This traceback arises when  the user tries to remove the start date

Steps to produce

1. Install 'resource'
2. Open 'Settings/Technical/resource/Resource Time Off'
3. Create a new record and remove start date

AttributeError
'bool' object has no attribute 'tzinfo'

when the user tries to remove the start date, an error will be
produced because _compute_date_to seems to be computing the date_to
based on the date_from field. when removing the date_from  from calculations
on empty or none

which leads to traceback from here
https://github.com/odoo/odoo/blob/322e7ea19b7c069fdb92d3b86e5615c55489ca21/addons/resource/models/resource_calendar_leaves.py#L54-L59

This commit solves the above issue by computing `date_to` for records that have
`date_from`. Apart from that, this commit also removes `# -*- coding: utf-8 -*-`
from the first line of the modified file.

sentry-4983497879

closes odoo/odoo#163311

X-original-commit: 5032a8ffed10bfbd619c85a266092f129716ceca
Signed-off-by: Bertrand Dossogne (bedo) <bedo@odoo.com>
2024-04-25 17:06:57 +00:00

80 lines
4.0 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime, time
from dateutil.relativedelta import relativedelta
from pytz import timezone, utc
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
class ResourceCalendarLeaves(models.Model):
_name = "resource.calendar.leaves"
_description = "Resource Time Off Detail"
_order = "date_from"
def default_get(self, fields_list):
res = super().default_get(fields_list)
if 'date_from' in fields_list and 'date_to' in fields_list and not res.get('date_from') and not res.get('date_to'):
# Then we give the current day and we search the begin and end hours for this day in resource.calendar of the current company
today = fields.Datetime.now()
user_tz = timezone(self.env.user.tz or self._context.get('tz') or self.company_id.resource_calendar_id.tz or 'UTC')
date_from = user_tz.localize(datetime.combine(today, time.min))
date_to = user_tz.localize(datetime.combine(today, time.max))
intervals = self.env.company.resource_calendar_id._work_intervals_batch(date_from.replace(tzinfo=utc), date_to.replace(tzinfo=utc))[False]
if intervals: # Then we stop and return the dates given in parameter
list_intervals = [(start, stop) for start, stop, records in intervals] # Convert intervals in interval list
date_from = list_intervals[0][0] # We take the first date in the interval list
date_to = list_intervals[-1][1] # We take the last date in the interval list
res.update(
date_from=date_from.astimezone(utc).replace(tzinfo=None),
date_to=date_to.astimezone(utc).replace(tzinfo=None)
)
return res
name = fields.Char('Reason')
company_id = fields.Many2one(
'res.company', string="Company", readonly=True, store=True,
default=lambda self: self.env.company, compute='_compute_company_id')
calendar_id = fields.Many2one('resource.calendar', 'Working Hours', domain="[('company_id', 'in', [company_id, False])]", check_company=True, index=True)
date_from = fields.Datetime('Start Date', required=True)
date_to = fields.Datetime('End Date', compute="_compute_date_to", readonly=False, required=True, store=True)
resource_id = fields.Many2one(
"resource.resource", 'Resource', index=True,
help="If empty, this is a generic time off for the company. If a resource is set, the time off is only for this resource")
time_type = fields.Selection([('leave', 'Time Off'), ('other', 'Other')], default='leave',
help="Whether this should be computed as a time off or as work time (eg: formation)")
@api.depends('calendar_id')
def _compute_company_id(self):
for leave in self:
leave.company_id = leave.calendar_id.company_id or self.env.company
@api.depends('date_from')
def _compute_date_to(self):
user_tz = timezone(self.env.user.tz or self._context.get('tz') or self.company_id.resource_calendar_id.tz or 'UTC')
for leave in self:
if not leave.date_from:
continue
date_to_tz = user_tz.localize(leave.date_from) + relativedelta(hour=23, minute=59, second=59)
leave.date_to = date_to_tz.astimezone(utc).replace(tzinfo=None)
@api.constrains('date_from', 'date_to')
def check_dates(self):
if self.filtered(lambda leave: leave.date_from > leave.date_to):
raise ValidationError(_('The start date of the time off must be earlier than the end date.'))
@api.onchange('resource_id')
def onchange_resource(self):
if self.resource_id:
self.calendar_id = self.resource_id.calendar_id
def _copy_leave_vals(self):
self.ensure_one()
return {
'name': self.name,
'date_from': self.date_from,
'date_to': self.date_to,
'time_type': self.time_type,
}