GOLEM/golem_activity_session/models/golem_activity_session.py

220 lines
8.6 KiB
Python

# -*- coding: utf-8 -*-
# copyright 2016 fabien bourgeois <fabien@yaltik.com>
#
# this program is free software: you can redistribute it and/or modify
# it under the terms of the gnu affero general public license as
# published by the free software foundation, either version 3 of the
# license, or (at your option) any later version.
#
# this program is distributed in the hope that it will be useful,
# but without any warranty; without even the implied warranty of
# merchantability or fitness for a particular purpose. see the
# gnu affero general public license for more details.
#
# you should have received a copy of the gnu affero general public license
# along with this program. if not, see <http://www.gnu.org/licenses/>.
from openerp import models, fields, api, _
class GolemMember(models.Model):
_inherit = 'golem.member'
activity_session_ids = fields.Many2many('golem.activity.session',
string='Activities')
class GolemActivity(models.Model):
_inherit = 'golem.activity'
session_count = fields.Integer('Sessions',
compute='_compute_session_count')
@api.one
def _compute_session_count(self):
dmn = [('activity_id', '=', self.id)]
cnt = self.env['golem.activity.session'].search_count(dmn)
self.session_count = cnt
@api.multi
def button_session(self):
self.ensure_one()
return {'name': _('Activity Sessions'),
'type': 'ir.actions.act_window',
'res_model': 'golem.activity.session',
'view_mode': 'tree,form',
'context': {'default_activity_id': self.id,
'default_animator_id': self.animator_id.id},
'domain': [('activity_id', '=', self.id)]}
class ProductTemplate(models.Model):
_inherit = 'product.template'
# Make default service for type
type = fields.Selection(default='service')
class GolemActivitySession(models.Model):
_name = 'golem.activity.session'
_description = 'GOLEM Activities Sessions'
_inherit = 'mail.thread'
_inherits = {'product.template': 'product_id'}
product_id = fields.Many2one('product.template', required=True,
ondelete='cascade')
default_code = fields.Char(copy=True) # Copy the default code
@api.model
def _default_name(self):
""" Default name to activity name """
d_aid = self.env.context.get('default_activity_id')
aobj = self.env['golem.activity']
return aobj.browse([d_aid]).name if d_aid else None
image = fields.Binary(related='activity_id.image')
categ_id = fields.Many2one(related='activity_id.categ_id', readonly=True)
session_name = fields.Char('Name', compute='_compute_full_name',
store=True, index=True)
@api.depends('name', 'default_code')
def _compute_full_name(self):
""" Provide a better displayed name """
for s in self:
session_name = unicode(s.name)
if s.default_code:
session_name = u'[{}] {}'.format(s.default_code, session_name)
s.session_name = session_name
member_ids = fields.Many2many('golem.member', string='Members')
places_used = fields.Integer('Places used', compute='_compute_places_used')
@api.depends('member_ids')
def _compute_places_used(self):
for s in self:
s.places_used = len(s.member_ids)
# TODO: to link with calendar.event
activity_id = fields.Many2one('golem.activity', string='Activity',
required=True)
animator_id = fields.Many2one('res.partner', string='Animator')
is_current = fields.Boolean('Current season?',
related='activity_id.is_current')
season_id = fields.Many2one(string='Season',
related='activity_id.season_id')
@api.onchange('activity_id')
def onchange_activity_id(self):
""" Sets session name and animator as activity's one if empty """
for s in self:
if not s.name:
s.name = s.activity_id.name
if not s.animator_id:
s.animator_id = s.activity_id.animator_id
is_recurrent = fields.Boolean('Is recurrent ?', default=True,
help='Work in progress')
date_start = fields.Datetime('Start date')
date_end = fields.Datetime('End date')
@api.onchange('date_start')
def onchange_date_start(self):
""" Sets end date to start date if no start date """
for s in self:
if not s.date_end:
s.date_end = s.date_start
@api.constrains('date_start', 'date_end')
def _check_date_period(self):
""" Check if end date if after start date and if dates are included
into main activity period"""
for s in self:
if not s.is_recurrent:
if s.date_start > s.date_end:
emsg = _('Start of the session cannot be after end of the '
'session.')
raise models.ValidationError(emsg)
if s.date_start < s.activity_id.date_start:
emsg = _('Start of the session cannot be before the start '
'of activity date')
raise models.ValidationError(emsg)
if s.date_end > s.activity_id.date_end:
emsg = _('End of the session cannot be after the end of '
'activity date')
raise models.ValidationError(emsg)
weekday = fields.Selection([('mon', _('Monday')),
('tue', _('Tuesday')),
('wed', _('Wednesday')),
('thu', _('Thursday')),
('fri', _('Friday')),
('sat', _('Saturday')),
('sun', _('Sunday'))])
hour_start = fields.Float('Start time')
hour_end = fields.Float('End time')
@api.onchange('hour_start')
def onchange_hour_start(self):
""" Sets end hour to start hour if no start hour """
for s in self:
if not s.hour_end:
s.hour_end = s.hour_start
@api.constrains('hour_start', 'hour_end')
def _check_hour_period(self):
""" Check if end hour if after start hour """
for s in self:
if s.hour_start > s.hour_end:
raise models.ValidationError(_('Start of the period cannot be '
'after end of the period.'))
places = fields.Integer('Places', default=0)
places_min = fields.Integer('Minimum places', default=0,
help='Minimum places to maintain the session')
is_overbooked = fields.Boolean('Allow overbook?', default=False)
places_overbooked = fields.Integer('Places with overbook', default=0)
places_remain = fields.Integer('Remaining places', store=True,
compute='_compute_places_remain')
@api.depends('places', 'is_overbooked', 'places_overbooked', 'member_ids')
def _compute_places_remain(self):
for s in self:
used = len(s.member_ids)
if not s.is_overbooked:
s.places_remain = s.places - used
else:
s.places_remain = s.places_overbooked - used
@api.constrains('places_remain')
def _check_remaining_places(self):
""" Forbid inscription when there is no more place """
for s in self:
if s.places_remain < 0:
emsg = _('Sorry, there is no more place !')
raise models.ValidationError(emsg)
@api.onchange('is_overbooked', 'places')
def onchange_is_overbooked(self):
for s in self:
if s.places and s.is_overbooked:
if not s.places_overbooked or (s.places_overbooked < s.places):
s.places_overbooked = s.places + 1
@api.constrains('places', 'places_overbooked')
def _check_places(self):
""" Check integers are signed and overbooked to be superior than
normal places """
for v in self:
for f in ['places', 'places_overbooked']:
if v[f] < 0:
emsg = _('Number of places cannot be negative.')
raise models.ValidationError(emsg)
if v.is_overbooked and (v.places_overbooked <= v.places):
emsg = _('Overbooked places cannot be inferior than places')
raise models.ValidationError(emsg)
note = fields.Text('Note')