From d1c178aa8ca760a74cf33cc037d5e269f1e38841 Mon Sep 17 00:00:00 2001 From: Fabien BOURGEOIS Date: Sun, 18 Feb 2018 16:41:01 +0100 Subject: [PATCH] [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 --- .../models/golem_resource_reservation.py | 113 +++++++++++------- golem_resource/security/ir.model.access.csv | 2 +- 2 files changed, 71 insertions(+), 44 deletions(-) diff --git a/golem_resource/models/golem_resource_reservation.py b/golem_resource/models/golem_resource_reservation.py index b54a8d59..c860b9ff 100644 --- a/golem_resource/models/golem_resource_reservation.py +++ b/golem_resource/models/golem_resource_reservation.py @@ -20,7 +20,7 @@ from math import modf from odoo import models, fields, api, _ -from odoo.exceptions import UserError +from odoo.exceptions import UserError, ValidationError class GolemResourceReservation(models.Model): @@ -30,28 +30,33 @@ class GolemResourceReservation(models.Model): name = fields.Char(compute='_compute_name', store=True) # TODO: handle multiple days reservation - date = fields.Date(required=True, index=True) - hour_start = fields.Float('Start hour', required=True) - hour_stop = fields.Float('Stop hour', required=True) + date = fields.Date(required=True, index=True, readonly=True, + states={'draft': [('readonly', False)]}) + 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_stop = fields.Datetime(compute='_compute_date_stop', store=True, index=True) resource_id = fields.Many2one('golem.resource', required=True, index=True, - string='Resource') - user_id = fields.Many2one('res.users', required=True, index=True, - string='User', - default=lambda self: self.env.user) + string='Resource', readonly=True, + states={'draft': [('readonly', False)]}) + user_id = fields.Many2one('res.users', required=True, index=True, readonly=True, + string='User', default=lambda self: self.env.user, + states={'draft': [('readonly', False)]}) partner_id = fields.Many2one('res.partner', string='On behalf of', - required=True, index=True) - status = fields.Selection([ + required=True, index=True, readonly=True, + states={'draft': [('readonly', False)]}) + state = fields.Selection([ + ('canceled', 'Canceled'), ('draft', 'Draft'), ('confirmed', 'Confirmed'), - ('canceled', 'Canceled'), ('validated', 'Validated'), - ('rejected', 'Rejected'), + ('rejected', 'Rejected') ], default='draft') - rejection_reason = fields.Text() + rejection_reason = fields.Text(readonly=True) @api.depends('resource_id', 'date') def _compute_name(self): @@ -64,47 +69,63 @@ class GolemResourceReservation(models.Model): def _compute_date_start(self): """ Computes Date start """ 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)) - reservation.date_start = u'{} {}:{}'.format(reservation.date, - hour_start, minute_start) + reservation.date_start = u'{} {}:{}:00'.format(reservation.date, + hour_start, minute_start) @api.depends('date', 'hour_stop') def _compute_date_stop(self): """ Computes Date stop """ 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)) - reservation.date_stop = u'{} {}:{}'.format(reservation.date, - hour_stop, minute_stop) + reservation.date_stop = u'{} {}:{}:00'.format(reservation.date, + 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 - def status_draft(self): + def state_draft(self): """ Status to draft """ - self.write({'status': 'draft'}) + self.write({'state': 'draft'}) @api.multi - def status_confirm(self): + def state_confirm(self): """ Confirms reservation, or validates it if not workflow is involved """ for reservation in self: - if reservation.resource_id.validation_required: - reservation.status = 'confirmed' - else: - reservation.status_validated() + # Needed, for constraint checking + reservation.state = 'confirmed' + if not reservation.resource_id.validation_required: + reservation.state = 'validated' @api.multi - def status_canceled(self): + def state_canceled(self): """ Status to cancel """ - self.write({'status': 'canceled'}) + self.write({'state': 'canceled'}) @api.multi - def status_validated(self): + def state_validated(self): """ Status to validated """ - self.write({'status': 'validated'}) + self.write({'state': 'validated'}) @api.multi - def status_rejected(self): + def state_rejected(self): """ Wizard call for reservation reject """ self.ensure_one() reservation_id = self[0] @@ -116,11 +137,20 @@ class GolemResourceReservation(models.Model): '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): """ Check date coherence on reservation confirmation """ 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 if reservation.date < reservation.resource_id.avaibility_start or \ reservation.date > reservation.resource_id.avaibility_stop: @@ -135,8 +165,8 @@ class GolemResourceReservation(models.Model): date = fields.Datetime.from_string(reservation.date) if int(timetable.weekday) == date.weekday(): is_day_allowed = True - if reservation.hour_start < timetable.date_start or \ - reservation.hour_stop > timetable.date_stop: + if reservation.hour_start < timetable.time_start or \ + reservation.hour_stop > timetable.time_stop: uerr = _('Not allowed, the resource is not available ' 'during this period, please choose another ' 'time before confirming.') @@ -149,17 +179,14 @@ class GolemResourceReservation(models.Model): # PERF : check the date, not iterate over all reservations domain = [('resource_id', '=', reservation.resource_id.id), ('date', '=', reservation.date), - ('status', '=', 'confirmed'), + ('state', 'in', ('confirmed', 'validated')), ('id', '!=', reservation.id)] reservations = self.env['golem.resource.reservation'].search(domain) for other_res in reservations: - if (other_res.hour_start < reservation.hour_start < other_res.hour_stop) or \ - (other_res.hour_start < reservation.hour_stop < other_res.hour_stop): + if (other_res.hour_start <= reservation.hour_start <= other_res.hour_stop) or \ + (other_res.hour_start <= reservation.hour_stop <= other_res.hour_stop): uerr = _('Not allowed, the resource is already taken ' 'during this period : from {} to {} this day, ' 'please choose another périod before confirming.') - raise UserError(uerr.format(reservation.date_start, - reservation.date_stop)) - # Finally, validate the reservation if all checks have passed - if reservation.resource_id.validation_required: - reservation.status = 'validated' + raise UserError(uerr.format(other_res.date_start, + other_res.date_stop)) diff --git a/golem_resource/security/ir.model.access.csv b/golem_resource/security/ir.model.access.csv index 8474a35e..88def47e 100644 --- a/golem_resource/security/ir.model.access.csv +++ b/golem_resource/security/ir.model.access.csv @@ -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_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_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_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