[IMP]GOLEM Resource : many enhancements like correct usage of states and readonly everytime but not on draft, access checking server side for validate/reject, fixes on main constraint

This commit is contained in:
Fabien BOURGEOIS 2018-02-18 16:41:01 +01:00
parent 2223b88930
commit d1c178aa8c
2 changed files with 71 additions and 44 deletions

View File

@ -20,7 +20,7 @@
from math import modf from math import modf
from odoo import models, fields, api, _ from odoo import models, fields, api, _
from odoo.exceptions import UserError from odoo.exceptions import UserError, ValidationError
class GolemResourceReservation(models.Model): class GolemResourceReservation(models.Model):
@ -30,28 +30,33 @@ class GolemResourceReservation(models.Model):
name = fields.Char(compute='_compute_name', store=True) name = fields.Char(compute='_compute_name', store=True)
# TODO: handle multiple days reservation # TODO: handle multiple days reservation
date = fields.Date(required=True, index=True) date = fields.Date(required=True, index=True, readonly=True,
hour_start = fields.Float('Start hour', required=True) states={'draft': [('readonly', False)]})
hour_stop = fields.Float('Stop hour', required=True) hour_start = fields.Float('Start hour', required=True, readonly=True,
states={'draft': [('readonly', False)]})
hour_stop = fields.Float('Stop hour', required=True, readonly=True,
states={'draft': [('readonly', False)]})
date_start = fields.Datetime(compute='_compute_date_start', store=True, index=True) date_start = fields.Datetime(compute='_compute_date_start', store=True, index=True)
date_stop = fields.Datetime(compute='_compute_date_stop', store=True, index=True) date_stop = fields.Datetime(compute='_compute_date_stop', store=True, index=True)
resource_id = fields.Many2one('golem.resource', required=True, index=True, resource_id = fields.Many2one('golem.resource', required=True, index=True,
string='Resource') string='Resource', readonly=True,
user_id = fields.Many2one('res.users', required=True, index=True, states={'draft': [('readonly', False)]})
string='User', user_id = fields.Many2one('res.users', required=True, index=True, readonly=True,
default=lambda self: self.env.user) string='User', default=lambda self: self.env.user,
states={'draft': [('readonly', False)]})
partner_id = fields.Many2one('res.partner', string='On behalf of', partner_id = fields.Many2one('res.partner', string='On behalf of',
required=True, index=True) required=True, index=True, readonly=True,
status = fields.Selection([ states={'draft': [('readonly', False)]})
state = fields.Selection([
('canceled', 'Canceled'),
('draft', 'Draft'), ('draft', 'Draft'),
('confirmed', 'Confirmed'), ('confirmed', 'Confirmed'),
('canceled', 'Canceled'),
('validated', 'Validated'), ('validated', 'Validated'),
('rejected', 'Rejected'), ('rejected', 'Rejected')
], default='draft') ], default='draft')
rejection_reason = fields.Text() rejection_reason = fields.Text(readonly=True)
@api.depends('resource_id', 'date') @api.depends('resource_id', 'date')
def _compute_name(self): def _compute_name(self):
@ -64,47 +69,63 @@ class GolemResourceReservation(models.Model):
def _compute_date_start(self): def _compute_date_start(self):
""" Computes Date start """ """ Computes Date start """
for reservation in self: for reservation in self:
hour_start, minute_start = modf(reservation.hour_start) minute_start, hour_start = modf(reservation.hour_start)
hour_start = int(hour_start)
minute_start = int(round(minute_start * 60)) minute_start = int(round(minute_start * 60))
reservation.date_start = u'{} {}:{}'.format(reservation.date, reservation.date_start = u'{} {}:{}:00'.format(reservation.date,
hour_start, minute_start) hour_start, minute_start)
@api.depends('date', 'hour_stop') @api.depends('date', 'hour_stop')
def _compute_date_stop(self): def _compute_date_stop(self):
""" Computes Date stop """ """ Computes Date stop """
for reservation in self: for reservation in self:
hour_stop, minute_stop = modf(reservation.hour_stop) minute_stop, hour_stop = modf(reservation.hour_stop)
hour_stop = int(hour_stop)
minute_stop = int(round(minute_stop * 60)) minute_stop = int(round(minute_stop * 60))
reservation.date_stop = u'{} {}:{}'.format(reservation.date, reservation.date_stop = u'{} {}:{}:00'.format(reservation.date,
hour_stop, minute_stop) hour_stop, minute_stop)
@api.onchange('hour_start')
def onchange_hour_start(self):
""" Propose automatically stop hour after start hour had been filled """
for reservation in self:
if reservation.hour_start and not reservation.hour_stop:
reservation.hour_stop = reservation.hour_start + 1
@api.constrains('hour_start', 'hour_stop')
def _check_hour_consistency(self):
""" Checks hour consistency """
for reservation in self:
if reservation.hour_stop < reservation.hour_start:
raise ValidationError(_('End time should be after than start time'))
@api.multi @api.multi
def status_draft(self): def state_draft(self):
""" Status to draft """ """ Status to draft """
self.write({'status': 'draft'}) self.write({'state': 'draft'})
@api.multi @api.multi
def status_confirm(self): def state_confirm(self):
""" Confirms reservation, or validates it if not workflow is involved """ """ Confirms reservation, or validates it if not workflow is involved """
for reservation in self: for reservation in self:
if reservation.resource_id.validation_required: # Needed, for constraint checking
reservation.status = 'confirmed' reservation.state = 'confirmed'
else: if not reservation.resource_id.validation_required:
reservation.status_validated() reservation.state = 'validated'
@api.multi @api.multi
def status_canceled(self): def state_canceled(self):
""" Status to cancel """ """ Status to cancel """
self.write({'status': 'canceled'}) self.write({'state': 'canceled'})
@api.multi @api.multi
def status_validated(self): def state_validated(self):
""" Status to validated """ """ Status to validated """
self.write({'status': 'validated'}) self.write({'state': 'validated'})
@api.multi @api.multi
def status_rejected(self): def state_rejected(self):
""" Wizard call for reservation reject """ """ Wizard call for reservation reject """
self.ensure_one() self.ensure_one()
reservation_id = self[0] reservation_id = self[0]
@ -116,11 +137,20 @@ class GolemResourceReservation(models.Model):
'target': 'new'} 'target': 'new'}
@api.constrains('status') @api.constrains('state')
def check_access(self):
""" Checks access when state is updated """
reservation = self[0]
if reservation.state in ('rejected', 'validated'):
if not self.env.user.has_group('golem_base.group_golem_manager'):
uerr = _('You do not have permissions to validate or reject a reservation.')
raise UserError(uerr)
@api.constrains('state')
def check_confirmed(self): def check_confirmed(self):
""" Check date coherence on reservation confirmation """ """ Check date coherence on reservation confirmation """
for reservation in self: for reservation in self:
if reservation.status == 'confirmed': if reservation.state == 'confirmed':
# Check is reservation is not taking place out of the resource avaibility period # Check is reservation is not taking place out of the resource avaibility period
if reservation.date < reservation.resource_id.avaibility_start or \ if reservation.date < reservation.resource_id.avaibility_start or \
reservation.date > reservation.resource_id.avaibility_stop: reservation.date > reservation.resource_id.avaibility_stop:
@ -135,8 +165,8 @@ class GolemResourceReservation(models.Model):
date = fields.Datetime.from_string(reservation.date) date = fields.Datetime.from_string(reservation.date)
if int(timetable.weekday) == date.weekday(): if int(timetable.weekday) == date.weekday():
is_day_allowed = True is_day_allowed = True
if reservation.hour_start < timetable.date_start or \ if reservation.hour_start < timetable.time_start or \
reservation.hour_stop > timetable.date_stop: reservation.hour_stop > timetable.time_stop:
uerr = _('Not allowed, the resource is not available ' uerr = _('Not allowed, the resource is not available '
'during this period, please choose another ' 'during this period, please choose another '
'time before confirming.') 'time before confirming.')
@ -149,17 +179,14 @@ class GolemResourceReservation(models.Model):
# PERF : check the date, not iterate over all reservations # PERF : check the date, not iterate over all reservations
domain = [('resource_id', '=', reservation.resource_id.id), domain = [('resource_id', '=', reservation.resource_id.id),
('date', '=', reservation.date), ('date', '=', reservation.date),
('status', '=', 'confirmed'), ('state', 'in', ('confirmed', 'validated')),
('id', '!=', reservation.id)] ('id', '!=', reservation.id)]
reservations = self.env['golem.resource.reservation'].search(domain) reservations = self.env['golem.resource.reservation'].search(domain)
for other_res in reservations: for other_res in reservations:
if (other_res.hour_start < reservation.hour_start < other_res.hour_stop) or \ if (other_res.hour_start <= reservation.hour_start <= other_res.hour_stop) or \
(other_res.hour_start < reservation.hour_stop < other_res.hour_stop): (other_res.hour_start <= reservation.hour_stop <= other_res.hour_stop):
uerr = _('Not allowed, the resource is already taken ' uerr = _('Not allowed, the resource is already taken '
'during this period : from {} to {} this day, ' 'during this period : from {} to {} this day, '
'please choose another périod before confirming.') 'please choose another périod before confirming.')
raise UserError(uerr.format(reservation.date_start, raise UserError(uerr.format(other_res.date_start,
reservation.date_stop)) other_res.date_stop))
# Finally, validate the reservation if all checks have passed
if reservation.resource_id.validation_required:
reservation.status = 'validated'

View File

@ -3,7 +3,7 @@ access_golem_resource_user,Access GOLEM Resource User,model_golem_resource,golem
access_golem_resource_manager,Access GOLEM Resource Manager,model_golem_resource,golem_base.group_golem_manager,1,1,1,1 access_golem_resource_manager,Access GOLEM Resource Manager,model_golem_resource,golem_base.group_golem_manager,1,1,1,1
access_golem_resource_type_user,Access GOLEM Resource Type User,model_golem_resource_type,golem_base.group_golem_user,1,0,0,0 access_golem_resource_type_user,Access GOLEM Resource Type User,model_golem_resource_type,golem_base.group_golem_user,1,0,0,0
access_golem_resource_type_manager,Access GOLEM Resource Type Manager,model_golem_resource_type,golem_base.group_golem_manager,1,1,1,1 access_golem_resource_type_manager,Access GOLEM Resource Type Manager,model_golem_resource_type,golem_base.group_golem_manager,1,1,1,1
access_golem_resource_reservation_user,Access GOLEM Resource Reservation User,model_golem_resource_reservation,golem_base.group_golem_user,1,0,0,0 access_golem_resource_reservation_user,Access GOLEM Resource Reservation User,model_golem_resource_reservation,golem_base.group_golem_user,1,1,1,0
access_golem_resource_reservation_manager,Access GOLEM Resource Reservation Manager,model_golem_resource_reservation,golem_base.group_golem_manager,1,1,1,1 access_golem_resource_reservation_manager,Access GOLEM Resource Reservation Manager,model_golem_resource_reservation,golem_base.group_golem_manager,1,1,1,1
access_golem_resource_timetable_user,Access GOLEM Resource Timetable User,model_golem_resource_timetable,golem_base.group_golem_user,1,0,0,0 access_golem_resource_timetable_user,Access GOLEM Resource Timetable User,model_golem_resource_timetable,golem_base.group_golem_user,1,0,0,0
access_golem_resource_timetable_manager,Access GOLEM Resource Timetable Manager,model_golem_resource_timetable,golem_base.group_golem_manager,1,1,1,1 access_golem_resource_timetable_manager,Access GOLEM Resource Timetable Manager,model_golem_resource_timetable,golem_base.group_golem_manager,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
3 access_golem_resource_manager Access GOLEM Resource Manager model_golem_resource golem_base.group_golem_manager 1 1 1 1
4 access_golem_resource_type_user Access GOLEM Resource Type User model_golem_resource_type golem_base.group_golem_user 1 0 0 0
5 access_golem_resource_type_manager Access GOLEM Resource Type Manager model_golem_resource_type golem_base.group_golem_manager 1 1 1 1
6 access_golem_resource_reservation_user Access GOLEM Resource Reservation User model_golem_resource_reservation golem_base.group_golem_user 1 0 1 0 1 0
7 access_golem_resource_reservation_manager Access GOLEM Resource Reservation Manager model_golem_resource_reservation golem_base.group_golem_manager 1 1 1 1
8 access_golem_resource_timetable_user Access GOLEM Resource Timetable User model_golem_resource_timetable golem_base.group_golem_user 1 0 0 0
9 access_golem_resource_timetable_manager Access GOLEM Resource Timetable Manager model_golem_resource_timetable golem_base.group_golem_manager 1 1 1 1