mirror of
https://gitlab.com/flectra-community/server-ux.git
synced 2024-11-24 15:12:05 +00:00
168 lines
6.9 KiB
Python
168 lines
6.9 KiB
Python
|
# Copyright 2016 ACSONE SA/NV (<https://acsone.eu>)
|
||
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||
|
|
||
|
from flectra import api, fields, models
|
||
|
from flectra.tools.translate import _
|
||
|
from flectra.exceptions import ValidationError
|
||
|
|
||
|
|
||
|
class DateRange(models.Model):
|
||
|
_name = "date.range"
|
||
|
_description = "Date Range"
|
||
|
_order = "type_name,date_start"
|
||
|
|
||
|
@api.model
|
||
|
def _default_company(self):
|
||
|
return self.env['res.company']._company_default_get('date.range')
|
||
|
|
||
|
name = fields.Char(required=True, translate=True)
|
||
|
date_start = fields.Date(string='Start date', required=True)
|
||
|
date_end = fields.Date(string='End date', required=True)
|
||
|
type_id = fields.Many2one(
|
||
|
comodel_name='date.range.type', string='Type', index=1, required=True,
|
||
|
ondelete='restrict', domain="['|', ('company_id', '=', company_id), "
|
||
|
"('company_id', '=', False)]")
|
||
|
type_name = fields.Char(
|
||
|
string='Type', related='type_id.name', readonly=True, store=True)
|
||
|
company_id = fields.Many2one(
|
||
|
comodel_name='res.company', string='Company', index=1,
|
||
|
default=_default_company)
|
||
|
active = fields.Boolean(
|
||
|
help="The active field allows you to hide the date range without "
|
||
|
"removing it.", default=True)
|
||
|
parent_type_id = fields.Many2one(
|
||
|
related='type_id.parent_type_id',
|
||
|
store=True,
|
||
|
readonly=True)
|
||
|
parent_id = fields.Many2one(
|
||
|
comodel_name='date.range', string="Parent", index=1)
|
||
|
|
||
|
_sql_constraints = [
|
||
|
('date_range_uniq', 'unique (name,type_id, company_id, parent_id)',
|
||
|
'A date range must be unique per company and parent!')]
|
||
|
|
||
|
@api.onchange('company_id', 'type_id')
|
||
|
def _onchange_company_id(self):
|
||
|
if self.company_id and self.type_id.company_id and \
|
||
|
self.type_id.company_id != self.company_id:
|
||
|
self._cache.update(
|
||
|
self._convert_to_cache({'type_id': False}, update=True))
|
||
|
|
||
|
@api.multi
|
||
|
@api.constrains('company_id', 'type_id')
|
||
|
def _check_company_id_type_id(self):
|
||
|
for rec in self.sudo():
|
||
|
if rec.company_id and rec.type_id.company_id and\
|
||
|
rec.company_id != rec.type_id.company_id:
|
||
|
raise ValidationError(
|
||
|
_('The Company in the Date Range and in '
|
||
|
'Date Range Type must be the same.'))
|
||
|
|
||
|
@api.constrains('parent_id', 'date_start', 'date_end')
|
||
|
def _validate_child_range(self):
|
||
|
for this in self:
|
||
|
if not this.parent_id:
|
||
|
continue
|
||
|
date_start_valid = this.parent_id.date_start <= this.date_start
|
||
|
date_end_valid = this.parent_id.date_end >= this.date_end
|
||
|
if date_start_valid and date_end_valid:
|
||
|
continue
|
||
|
text_dict = {
|
||
|
'name': this.name,
|
||
|
'start': this.date_start,
|
||
|
'end': this.date_end,
|
||
|
'parent_name': this.parent_id.name,
|
||
|
'parent_start': this.parent_id.date_start,
|
||
|
'parent_end': this.parent_id.date_end,
|
||
|
}
|
||
|
if (not date_start_valid) and date_end_valid:
|
||
|
text = _(
|
||
|
"Start date %(start)s of %(name)s must be greater than"
|
||
|
" or equal to "
|
||
|
"start date %(parent_start)s of %(parent_name)s"
|
||
|
) % text_dict
|
||
|
elif (not date_end_valid) and date_start_valid:
|
||
|
text = _(
|
||
|
"End date %(end)s of %(name)s must be smaller than"
|
||
|
" or equal to "
|
||
|
"end date %(parent_end)s of %(parent_name)s"
|
||
|
) % text_dict
|
||
|
else:
|
||
|
text = _(
|
||
|
"%(name)s range not in "
|
||
|
"%(parent_start)s - %(parent_end)s"
|
||
|
) % text_dict
|
||
|
raise ValidationError(
|
||
|
_("%(name)s not a subrange of"
|
||
|
" %(parent_name)s: " % text_dict) + text
|
||
|
)
|
||
|
|
||
|
@api.constrains('type_id', 'date_start', 'date_end', 'company_id')
|
||
|
def _validate_range(self):
|
||
|
for this in self:
|
||
|
start = fields.Date.from_string(this.date_start)
|
||
|
end = fields.Date.from_string(this.date_end)
|
||
|
if start > end:
|
||
|
raise ValidationError(
|
||
|
_("%s is not a valid range (%s > %s)") % (
|
||
|
this.name, this.date_start, this.date_end))
|
||
|
if this.type_id.allow_overlap:
|
||
|
continue
|
||
|
# here we use a plain SQL query to benefit of the daterange
|
||
|
# function available in PostgresSQL
|
||
|
# (http://www.postgresql.org/docs/current/static/rangetypes.html)
|
||
|
SQL = """
|
||
|
SELECT
|
||
|
id
|
||
|
FROM
|
||
|
date_range dt
|
||
|
WHERE
|
||
|
DATERANGE(dt.date_start, dt.date_end, '[]') &&
|
||
|
DATERANGE(%s::date, %s::date, '[]')
|
||
|
AND dt.id != %s
|
||
|
AND dt.active
|
||
|
AND dt.company_id = %s
|
||
|
AND dt.type_id=%s;"""
|
||
|
self.env.cr.execute(SQL, (this.date_start,
|
||
|
this.date_end,
|
||
|
this.id,
|
||
|
this.company_id.id or None,
|
||
|
this.type_id.id))
|
||
|
res = self.env.cr.fetchall()
|
||
|
if res:
|
||
|
dt = self.browse(res[0][0])
|
||
|
raise ValidationError(
|
||
|
_("%s overlaps %s") % (this.name, dt.name))
|
||
|
|
||
|
@api.multi
|
||
|
def get_domain(self, field_name):
|
||
|
self.ensure_one()
|
||
|
return [(field_name, '>=', self.date_start),
|
||
|
(field_name, '<=', self.date_end)]
|
||
|
|
||
|
@api.multi
|
||
|
@api.onchange('company_id', 'type_id', 'date_start', 'date_end')
|
||
|
def onchange_type_id(self):
|
||
|
"""The type_id and the dates determine the choices for parent."""
|
||
|
domain = []
|
||
|
if self.company_id:
|
||
|
domain.append(('company_id', '=', self.company_id.id))
|
||
|
if self.parent_type_id:
|
||
|
domain.append(('type_id', '=', self.parent_type_id.id))
|
||
|
if self.date_start:
|
||
|
domain.append('|')
|
||
|
domain.append(('date_start', '<=', self.date_start))
|
||
|
domain.append(('date_start', '=', False))
|
||
|
if self.date_end:
|
||
|
domain.append('|')
|
||
|
domain.append(('date_end', '>=', self.date_end))
|
||
|
domain.append(('date_end', '=', False))
|
||
|
if domain:
|
||
|
# If user did not select a parent already, autoselect the last
|
||
|
# (ordered by date_start) or only parent that applies.
|
||
|
if self.type_id and self.date_start and not self.parent_id:
|
||
|
possible_parent = self.search(
|
||
|
domain, limit=1, order='date_start desc')
|
||
|
self.parent_id = possible_parent # can be empty!
|
||
|
return {'domain': {'parent_id': domain}}
|