summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
Diffstat (limited to 'addons')
-rw-r--r--addons/event/models/event_event.py207
-rw-r--r--addons/event/models/event_registration.py64
-rw-r--r--addons/event/tests/common.py2
-rw-r--r--addons/event/tests/test_event_flow.py5
-rw-r--r--addons/event/tests/test_event_internals.py27
-rw-r--r--addons/event/tests/test_event_mail_schedule.py1
-rw-r--r--addons/event/tests/test_event_security.py6
-rw-r--r--addons/event_sale/tests/test_event_internals.py3
-rw-r--r--addons/website_event/models/event_event.py21
-rw-r--r--addons/website_event_questions/models/event_event.py29
-rw-r--r--addons/website_event_questions/tests/test_event_internals.py2
-rw-r--r--addons/website_event_sale/tests/test_frontend_buy_tickets.py8
12 files changed, 223 insertions, 152 deletions
diff --git a/addons/event/models/event_event.py b/addons/event/models/event_event.py
index e5f89ecf884..a1fd7ae8df7 100644
--- a/addons/event/models/event_event.py
+++ b/addons/event/models/event_event.py
@@ -24,21 +24,6 @@ class EventType(models.Model):
_description = 'Event Category'
_order = 'sequence, id'
- @api.model
- def _get_default_event_type_mail_ids(self):
- return [(0, 0, {
- 'notification_type': 'mail',
- 'interval_unit': 'now',
- 'interval_type': 'after_sub',
- 'template_id': self.env.ref('event.event_subscription').id,
- }), (0, 0, {
- 'notification_type': 'mail',
- 'interval_nbr': 10,
- 'interval_unit': 'days',
- 'interval_type': 'before_event',
- 'template_id': self.env.ref('event.event_reminder').id,
- })]
-
name = fields.Char('Event Category', required=True, translate=True)
sequence = fields.Integer()
# tickets
@@ -50,7 +35,8 @@ class EventType(models.Model):
# registration
has_seats_limitation = fields.Boolean('Limited Seats')
default_registration_max = fields.Integer(
- 'Maximum Registrations', default=0,
+ 'Maximum Registrations', compute='_compute_default_registration',
+ copy=True, readonly=False, store=True,
help="It will select this default maximum value when you choose this event")
auto_confirm = fields.Boolean(
'Automatically Confirm Registrations', default=True,
@@ -66,9 +52,28 @@ class EventType(models.Model):
use_mail_schedule = fields.Boolean(
'Automatically Send Emails', default=True)
event_type_mail_ids = fields.One2many(
- 'event.type.mail', 'event_type_id', string='Mail Schedule',
- copy=False,
- default=lambda self: self._get_default_event_type_mail_ids())
+ 'event.type.mail', 'event_type_id',
+ string='Mail Schedule', compute='_compute_event_type_mail_ids',
+ readonly=False, store=True)
+
+ @api.depends('use_mail_schedule')
+ def _compute_event_type_mail_ids(self):
+ for template in self:
+ if not template.use_mail_schedule:
+ template.event_type_mail_ids = [(5, 0)]
+ elif not template.event_type_mail_ids:
+ template.event_type_mail_ids = [(0, 0, {
+ 'notification_type': 'mail',
+ 'interval_unit': 'now',
+ 'interval_type': 'after_sub',
+ 'template_id': self.env.ref('event.event_subscription').id,
+ }), (0, 0, {
+ 'notification_type': 'mail',
+ 'interval_nbr': 10,
+ 'interval_unit': 'days',
+ 'interval_type': 'before_event',
+ 'template_id': self.env.ref('event.event_reminder').id,
+ })]
@api.depends('use_ticket')
def _compute_event_type_ticket_ids(self):
@@ -80,10 +85,11 @@ class EventType(models.Model):
'name': _('Registration'),
})]
- @api.onchange('has_seats_limitation')
- def _onchange_has_seats_limitation(self):
- if not self.has_seats_limitation:
- self.default_registration_max = 0
+ @api.depends('has_seats_limitation')
+ def _compute_default_registration(self):
+ for template in self:
+ if not template.has_seats_limitation:
+ template.default_registration_max = 0
class EventEvent(models.Model):
@@ -114,10 +120,14 @@ class EventEvent(models.Model):
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
event_type_id = fields.Many2one('event.type', string='Category', ondelete='set null')
color = fields.Integer('Kanban Color Index')
- event_mail_ids = fields.One2many('event.mail', 'event_id', string='Mail Schedule', copy=True)
+ event_mail_ids = fields.One2many(
+ 'event.mail', 'event_id', string='Mail Schedule', copy=True,
+ compute='_compute_from_event_type', readonly=False, store=True)
# Kanban fields
kanban_state = fields.Selection([('normal', 'In Progress'), ('done', 'Done'), ('blocked', 'Blocked')], default='normal')
- kanban_state_label = fields.Char(compute='_compute_kanban_state_label', string='Kanban State Label', tracking=True, store=True)
+ kanban_state_label = fields.Char(
+ string='Kanban State Label', compute='_compute_kanban_state_label',
+ store=True, tracking=True)
stage_id = fields.Many2one(
'event.stage', ondelete='restrict', default=_get_default_stage_id,
group_expand='_read_group_stage_ids', tracking=True)
@@ -127,10 +137,12 @@ class EventEvent(models.Model):
# Seats and computation
seats_max = fields.Integer(
string='Maximum Attendees Number',
+ compute='_compute_from_event_type', copy=True, readonly=False, store=True,
help="For each event you can define a maximum registration of seats(number of attendees), above this numbers the registrations are not accepted.")
seats_availability = fields.Selection(
[('unlimited', 'Unlimited'), ('limited', 'Limited')],
- 'Maximum Attendees', required=True, default='unlimited')
+ string='Maximum Attendees', required=True,
+ compute='_compute_seats_availability', copy=True, readonly=False, store=True)
seats_reserved = fields.Integer(
string='Reserved Seats',
store=True, readonly=True, compute='_compute_seats')
@@ -147,16 +159,18 @@ class EventEvent(models.Model):
string='Number of Expected Attendees',
compute_sudo=True, readonly=True, compute='_compute_seats')
# Registration fields
- auto_confirm = fields.Boolean(string='Autoconfirm Registrations')
+ auto_confirm = fields.Boolean(
+ string='Autoconfirm Registrations',
+ compute='_compute_from_event_type', copy=True, readonly=False, store=True)
registration_ids = fields.One2many('event.registration', 'event_id', string='Attendees')
event_registrations_open = fields.Boolean('Registration open', compute='_compute_event_registrations_open')
event_ticket_ids = fields.One2many(
- 'event.event.ticket', 'event_id', string='Event Ticket',
- copy=True)
+ 'event.event.ticket', 'event_id', string='Event Ticket', copy=True,
+ compute='_compute_from_event_type', readonly=False, store=True)
# Date fields
date_tz = fields.Selection(
_tz_get, string='Timezone', required=True,
- default=lambda self: self.env.user.tz or 'UTC')
+ compute='_compute_date_tz', copy=True, readonly=False, store=True)
date_begin = fields.Datetime(string='Start Date', required=True, tracking=True)
date_end = fields.Datetime(string='End Date', required=True, tracking=True)
date_begin_located = fields.Char(string='Start Date Located', compute='_compute_date_begin_tz')
@@ -165,12 +179,16 @@ class EventEvent(models.Model):
is_one_day = fields.Boolean(compute='_compute_field_is_one_day')
start_sale_date = fields.Date('Start sale date', compute='_compute_start_sale_date')
# Location and communication
- is_online = fields.Boolean('Online Event')
+ is_online = fields.Boolean(
+ string='Online Event', compute='_compute_from_event_type',
+ copy=True, readonly=False, store=True)
address_id = fields.Many2one(
- 'res.partner', string='Venue', tracking=True,
- default=lambda self: self.env.company.partner_id,
+ 'res.partner', string='Venue', compute='_compute_address_id',
+ copy=True, readonly=False, store=True, tracking=True,
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
- country_id = fields.Many2one('res.country', 'Country', related='address_id.country_id', store=True, readonly=False)
+ country_id = fields.Many2one(
+ 'res.country', 'Country', related='address_id.country_id',
+ copy=True, readonly=False, store=True)
# badge fields
badge_front = fields.Html(string='Badge Front')
badge_back = fields.Html(string='Badge Back')
@@ -282,47 +300,86 @@ class EventEvent(models.Model):
start_dates = [ticket.start_sale_date for ticket in event.event_ticket_ids if ticket.start_sale_date]
event.start_sale_date = min(start_dates) if start_dates else False
- @api.onchange('is_online')
- def _onchange_is_online(self):
- if self.is_online:
- self.address_id = False
-
- @api.onchange('event_type_id')
- def _onchange_type(self):
- if self.event_type_id:
- self.seats_max = self.event_type_id.default_registration_max
- if self.event_type_id.default_registration_max:
- self.seats_availability = 'limited'
-
- if self.event_type_id.auto_confirm:
- self.auto_confirm = self.event_type_id.auto_confirm
-
- if self.event_type_id.use_timezone:
- self.date_tz = self.event_type_id.default_timezone
-
- self.is_online = self.event_type_id.is_online
+ @api.depends('is_online')
+ def _compute_address_id(self):
+ for event in self:
+ if event.is_online:
+ event.address_id = False
+ elif not event.address_id:
+ event.address_id = self.env.company.partner_id.id
- if self.event_type_id.use_mail_schedule and self.event_type_id.event_type_mail_ids:
- self.event_mail_ids = [(5, 0, 0)] + [
+ @api.depends('event_type_id')
+ def _compute_date_tz(self):
+ for event in self:
+ if event.event_type_id.use_timezone:
+ event.date_tz = event.event_type_id.default_timezone
+ if not event.date_tz:
+ event.date_tz = self.env.user.tz or 'UTC'
+
+ @api.depends('event_type_id')
+ def _compute_seats_availability(self):
+ """ Make it separate from ``_compute_from_event_type`` because otherwise
+ a value given at create (see create override) would protect all other fields
+ depending on event type id from being computed as compute method will be
+ blacklisted during create (see ``_field_computed`` attribute used in create
+ to compute protected field from re-computation) """
+ for event in self:
+ if event.event_type_id.default_registration_max:
+ event.seats_availability = 'limited'
+ if not event.seats_availability:
+ event.seats_availability = 'unlimited'
+
+ @api.depends('event_type_id')
+ def _compute_from_event_type(self):
+ """ Update event configuration from its event type. Depends are set only
+ on event_type_id itself, not its sub fields. Indeed purpose is to emulate
+ an onchange: if event type is changed, update event configuration. Changing
+ event type content itself should not trigger this method.
+
+ Updated by this method
+ * seats_max -> triggers _compute_seats (all seats computation)
+ * auto_confirm
+ * is_online -> triggers _compute_address_id (address_id computation)
+ * event_mail_ids
+ * event_ticket_ids -> triggers _compute_start_sale_date (start_sale_date computation)
+ """
+ for event in self:
+ if not event.event_type_id:
+ if not event.seats_max:
+ event.seats_max = 0
+ if not event.is_online:
+ event.is_online = False
+ if not event.event_ticket_ids:
+ event.event_ticket_ids = False
+ continue
+
+ if event.event_type_id.default_registration_max:
+ event.seats_max = event.event_type_id.default_registration_max
+
+ if event.event_type_id.auto_confirm:
+ event.auto_confirm = event.event_type_id.auto_confirm
+
+ event.is_online = event.event_type_id.is_online
+
+ # compute mailing information (force only if activated and mailing defined)
+ if event.event_type_id.use_mail_schedule and event.event_type_id.event_type_mail_ids:
+ event.event_mail_ids = [(5, 0, 0)] + [
(0, 0, {
attribute_name: line[attribute_name] if not isinstance(line[attribute_name], models.BaseModel) else line[attribute_name].id
for attribute_name in self.env['event.type.mail']._get_event_mail_fields_whitelist()
})
- for line in self.event_type_id.event_type_mail_ids]
-
- # compute tickets information
- if self.event_type_id.use_ticket:
- all_ticket_values = []
- for ticket in self.event_type_id.event_type_ticket_ids:
- ticket_vals = dict(
- (attribute_name, ticket[attribute_name] if not isinstance(ticket[attribute_name], models.BaseModel) else ticket[attribute_name].id)
- for attribute_name in self.env['event.type.ticket']._get_event_ticket_fields_whitelist()
- )
- all_ticket_values.append(ticket_vals)
+ for line in event.event_type_id.event_type_mail_ids]
- self.event_ticket_ids = [(5, 0, 0)] + [(0, 0, item) for item in all_ticket_values]
+ # compute tickets information (force only if activated and tickets defined)
+ if event.event_type_id.use_ticket and event.event_type_id.event_type_ticket_ids:
+ event.event_ticket_ids = [(5, 0, 0)] + [
+ (0, 0, {
+ attribute_name: line[attribute_name] if not isinstance(line[attribute_name], models.BaseModel) else line[attribute_name].id
+ for attribute_name in self.env['event.type.ticket']._get_event_ticket_fields_whitelist()
+ })
+ for line in event.event_type_id.event_type_ticket_ids]
- @api.constrains('seats_max', 'seats_available')
+ @api.constrains('seats_max', 'seats_available', 'seats_availability')
def _check_seats_limit(self):
if any(event.seats_availability == 'limited' and event.seats_max and event.seats_available < 0 for event in self):
raise ValidationError(_('No more available seats.'))
@@ -350,6 +407,9 @@ class EventEvent(models.Model):
@api.model
def create(self, vals):
+ # Temporary fix for ``seats_availability`` and ``date_tz`` required fields (see ``_compute_from_event_type``
+ vals.update(self._sync_required_computed(vals))
+
res = super(EventEvent, self).create(vals)
if res.organizer_id:
res.message_subscribe([res.organizer_id.id])
@@ -367,6 +427,17 @@ class EventEvent(models.Model):
default = dict(default or {}, name=_("%s (copy)") % (self.name))
return super(EventEvent, self).copy(default)
+ def _sync_required_computed(self, values):
+ """ Call compute fields in cache to find missing values for required fields
+ (seats_availability and date_tz) in case they are not given in values """
+ missing_fields = list(set(['seats_availability', 'date_tz']).difference(set(values.keys())))
+ if missing_fields and values:
+ cache_event = self.new(values)
+ cache_event._compute_from_event_type()
+ return dict((fname, cache_event[fname]) for fname in missing_fields)
+ else:
+ return {}
+
def action_set_done(self):
"""
Action which will move the events
diff --git a/addons/event/models/event_registration.py b/addons/event/models/event_registration.py
index 5f6c32a620b..b9d88dab020 100644
--- a/addons/event/models/event_registration.py
+++ b/addons/event/models/event_registration.py
@@ -29,13 +29,17 @@ class EventRegistration(models.Model):
partner_id = fields.Many2one(
'res.partner', string='Contact',
states={'done': [('readonly', True)]})
- name = fields.Char(string='Attendee Name', index=True, required=True, tracking=True)
- email = fields.Char(string='Email')
- phone = fields.Char(string='Phone')
- mobile = fields.Char(string='Mobile')
+ name = fields.Char(
+ string='Attendee Name', index=True,
+ compute='_compute_contact_info', copy=True, readonly=False, store=True, tracking=True)
+ email = fields.Char(string='Email', compute='_compute_contact_info', copy=True, readonly=False, store=True)
+ phone = fields.Char(string='Phone', compute='_compute_contact_info', copy=True, readonly=False, store=True)
+ mobile = fields.Char(string='Mobile', compute='_compute_contact_info', copy=True, readonly=False, store=True)
# organization
date_open = fields.Datetime(string='Registration Date', readonly=True, default=lambda self: fields.Datetime.now()) # weird crash is directly now
- date_closed = fields.Datetime(string='Attended Date', readonly=True)
+ date_closed = fields.Datetime(
+ string='Attended Date', compute='_compute_date_closed',
+ copy=True, readonly=False, store=True)
event_begin_date = fields.Datetime(string="Event Start Date", related='event_id.date_begin', readonly=True)
event_end_date = fields.Datetime(string="Event End Date", related='event_id.date_end', readonly=True)
company_id = fields.Many2one(
@@ -46,11 +50,23 @@ class EventRegistration(models.Model):
('open', 'Confirmed'), ('done', 'Attended')],
string='Status', default='draft', readonly=True, copy=False, tracking=True)
- @api.onchange('event_id')
- def _onchange_event_id(self):
- # We reset the ticket when keeping it would lead to an inconstitent state.
- if self.event_ticket_id and (not self.event_id or self.event_id != self.event_ticket_id.event_id):
- self.event_ticket_id = None
+ @api.depends('partner_id')
+ def _compute_contact_info(self):
+ for registration in self:
+ if registration.partner_id:
+ partner_vals = self._synchronize_partner_values(registration.partner_id)
+ registration.update(
+ dict((fname, fvalue)
+ for fname, fvalue in partner_vals.items()
+ if fvalue and not (registration[fname] or registration._origin[fname])
+ )
+ )
+
+ @api.depends('state')
+ def _compute_date_closed(self):
+ for registration in self:
+ if registration.state == 'done' and not registration.date_closed:
+ registration.date_closed = fields.Datetime.now()
@api.constrains('event_id', 'state')
def _check_seats_limit(self):
@@ -64,10 +80,10 @@ class EventRegistration(models.Model):
if record.event_ticket_id.seats_max and record.event_ticket_id.seats_available < 0:
raise ValidationError(_('No more available seats for this ticket'))
- @api.onchange('partner_id')
- def _onchange_partner(self):
- if self.partner_id:
- self.update(self._synchronize_partner_values(self.partner_id))
+ @api.constrains('event_id', 'event_ticket_id')
+ def _check_event_ticket(self):
+ if any(registration.event_id != registration.event_ticket_id.event_id for registration in self if registration.event_ticket_id):
+ raise ValidationError(_('Invalid event / ticket choice'))
# ------------------------------------------------------------
# CRUD
@@ -75,13 +91,6 @@ class EventRegistration(models.Model):
@api.model
def create(self, vals):
- # update missing pieces of information from partner
- if vals.get('partner_id'):
- partner_vals = self._synchronize_partner_values(
- self.env['res.partner'].browse(vals['partner_id'])
- )
- vals = dict(partner_vals, **vals)
-
registration = super(EventRegistration, self).create(vals)
if registration._check_auto_confirmation():
registration.sudo().action_confirm()
@@ -89,21 +98,8 @@ class EventRegistration(models.Model):
return registration
def write(self, vals):
- if vals.get('state') == 'done' and 'date_closed' not in vals:
- vals['date_closed'] = fields.Datetime.now()
-
ret = super(EventRegistration, self).write(vals)
- # update missing pieces of information from partner
- if vals.get('partner_id'):
- partner_vals = self._synchronize_partner_values(
- self.env['res.partner'].browse(vals['partner_id'])
- )
- for registration in self:
- partner_info = dict((key, val) for key, val in partner_vals.items() if not registration[key])
- if partner_info:
- registration.write(partner_info)
-
if vals.get('state') == 'open':
# auto-trigger after_sub (on subscribe) mail schedulers, if needed
onsubscribe_schedulers = self.mapped('event_id.event_mail_ids').filtered(lambda s: s.interval_type == 'after_sub')
diff --git a/addons/event/tests/common.py b/addons/event/tests/common.py
index f58722efcd1..8c32e558185 100644
--- a/addons/event/tests/common.py
+++ b/addons/event/tests/common.py
@@ -58,7 +58,7 @@ class TestEventCommon(common.SavepointCase):
'default_timezone': 'Europe/Paris',
'use_ticket': True,
'event_type_ticket_ids': [(0, 0, {
- 'name': 'First Ticket',
+ 'name': 'First Ticket',
}), (0, 0, {
'name': 'Second Ticket',
})
diff --git a/addons/event/tests/test_event_flow.py b/addons/event/tests/test_event_flow.py
index 572e64a8231..1ec9208e1b3 100644
--- a/addons/event/tests/test_event_flow.py
+++ b/addons/event/tests/test_event_flow.py
@@ -24,6 +24,7 @@ class TestEventFlow(TestEventCommon):
'seats_max': 2,
'seats_availability': 'limited',
})
+ self.assertTrue(test_event.auto_confirm)
# EventUser create registrations for this event
test_reg1 = self.env['event.registration'].with_user(self.user_eventuser).create({
@@ -56,15 +57,17 @@ class TestEventFlow(TestEventCommon):
@mute_logger('odoo.addons.base.models.ir_model', 'odoo.models')
def test_event_flow(self):
- """ Avanced event flow: no auto confirmation, manage minimum / maximum
+ """ Advanced event flow: no auto confirmation, manage minimum / maximum
seats, ... """
# EventUser creates a new event: ok
test_event = self.env['event.event'].with_user(self.user_eventmanager).create({
'name': 'TestEvent',
'date_begin': datetime.datetime.now() + relativedelta(days=-1),
'date_end': datetime.datetime.now() + relativedelta(days=1),
+ 'seats_availability': 'limited',
'seats_max': 10,
})
+ self.assertFalse(test_event.auto_confirm)
# EventUser create registrations for this event -> no auto confirmation
test_reg1 = self.env['event.registration'].with_user(self.user_eventuser).create({
diff --git a/addons/event/tests/test_event_internals.py b/addons/event/tests/test_event_internals.py
index 95e935972b3..b0ab686fa76 100644
--- a/addons/event/tests/test_event_internals.py
+++ b/addons/event/tests/test_event_internals.py
@@ -58,7 +58,7 @@ class TestEventData(TestEventCommon):
'date_begin': FieldsDatetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': FieldsDatetime.to_string(datetime.today() + timedelta(days=15)),
})
- event._onchange_type()
+
self.assertFalse(event.is_online)
self.assertEqual(event.address_id, self.env.user.company_id.partner_id)
# seats: coming from event type configuration
@@ -71,7 +71,6 @@ class TestEventData(TestEventCommon):
# set is_online: should reset the address_id field
event.update({'is_online': True})
- event._onchange_is_online()
self.assertTrue(event.is_online)
self.assertFalse(event.address_id)
@@ -112,14 +111,12 @@ class TestEventData(TestEventCommon):
event_type.write({
'use_mail_schedule': False,
})
- # Event type does not use mail schedule but data is kept for compatibility and avoid recreating them
- self.assertEqual(len(event_type.event_type_mail_ids), 2)
+ self.assertEqual(event_type.event_type_mail_ids, self.env['event.type.mail'])
event = self.env['event.event'].create({
'name': 'Event Update Type',
'date_begin': FieldsDatetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': FieldsDatetime.to_string(datetime.today() + timedelta(days=15)),
- 'auto_confirm': False,
'is_online': True,
})
self.assertEqual(event.date_tz, self.env.user.tz)
@@ -128,22 +125,18 @@ class TestEventData(TestEventCommon):
self.assertTrue(event.is_online)
self.assertEqual(event.event_mail_ids, self.env['event.mail'])
- event.update({'event_type_id': event_type.id})
- event._onchange_type()
- self.assertEqual(event.date_tz, 'Europe/Paris')
- self.assertEqual(event.seats_availability, 'limited')
- self.assertEqual(event.seats_max, event_type.default_registration_max)
- self.assertTrue(event.auto_confirm)
- self.assertFalse(event.is_online)
- self.assertEqual(event.event_mail_ids, self.env['event.mail'])
-
event_type.write({
'use_mail_schedule': True,
'event_type_mail_ids': [(5, 0), (0, 0, {
'interval_nbr': 1, 'interval_unit': 'days', 'interval_type': 'before_event',
'template_id': self.env['ir.model.data'].xmlid_to_res_id('event.event_reminder')})]
})
- event._onchange_type()
+ event.write({'event_type_id': event_type.id})
+ self.assertEqual(event.date_tz, 'Europe/Paris')
+ self.assertEqual(event.seats_availability, 'limited')
+ self.assertEqual(event.seats_max, event_type.default_registration_max)
+ self.assertTrue(event.auto_confirm)
+ self.assertFalse(event.is_online)
self.assertEqual(event.event_mail_ids.interval_nbr, 1)
self.assertEqual(event.event_mail_ids.interval_unit, 'days')
self.assertEqual(event.event_mail_ids.interval_type, 'before_event')
@@ -194,7 +187,7 @@ class TestEventData(TestEventCommon):
self.assertFalse(event.event_registrations_open)
@users('user_eventmanager')
- def test_ongoing_events(self):
+ def test_event_ongoing(self):
self.patcher = patch('odoo.addons.event.models.event_event.fields.Datetime', wraps=FieldsDatetime)
self.mock_datetime = self.patcher.start()
self.mock_datetime.now.return_value = datetime(2020, 1, 10, 8, 0, 0)
@@ -297,14 +290,12 @@ class TestEventTypeData(TestEventCommon):
'default_registration_max': 30,
'use_ticket': True,
})
- event_type._onchange_has_seats_limitation()
self.assertTrue(event_type.has_seats_limitation)
self.assertEqual(event_type.default_registration_max, 30)
self.assertEqual(event_type.event_type_ticket_ids.mapped('name'), ['Registration'])
# reset seats limitation
event_type.write({'has_seats_limitation': False})
- event_type._onchange_has_seats_limitation()
self.assertFalse(event_type.has_seats_limitation)
self.assertEqual(event_type.default_registration_max, 0)
diff --git a/addons/event/tests/test_event_mail_schedule.py b/addons/event/tests/test_event_mail_schedule.py
index ba1223ccc0f..42e1d18017d 100644
--- a/addons/event/tests/test_event_mail_schedule.py
+++ b/addons/event/tests/test_event_mail_schedule.py
@@ -22,7 +22,6 @@ class TestMailSchedule(TestEventCommon):
'auto_confirm': True,
'date_begin': event_date_begin,
'date_end': event_date_end,
- 'seats_max': 10,
'event_mail_ids': [
(0, 0, { # right at subscription
'interval_unit': 'now',
diff --git a/addons/event/tests/test_event_security.py b/addons/event/tests/test_event_security.py
index d2ac6d275a3..50cf81a84ec 100644
--- a/addons/event/tests/test_event_security.py
+++ b/addons/event/tests/test_event_security.py
@@ -26,6 +26,7 @@ class TestEventSecurity(TestEventCommon):
'name': 'TestEvent',
'date_begin': datetime.now() + relativedelta(days=-1),
'date_end': datetime.now() + relativedelta(days=1),
+ 'seats_availability': 'limited',
'seats_max': 10,
})
@@ -50,7 +51,6 @@ class TestEventSecurity(TestEventCommon):
'name': 'TestEvent',
'date_begin': datetime.now() + relativedelta(days=-1),
'date_end': datetime.now() + relativedelta(days=1),
- 'seats_max': 10,
})
with self.assertRaises(AccessError):
@@ -76,12 +76,10 @@ class TestEventSecurity(TestEventCommon):
})
event = self.env['event.event'].create({
'name': 'ManagerEvent',
+ 'event_type_id': event_type.id,
'date_begin': datetime.now() + relativedelta(days=-1),
'date_end': datetime.now() + relativedelta(days=1),
})
- event.update({'event_type_id': event_type.id})
- event._onchange_type()
- event.flush()
registration = self.env['event.registration'].create({'event_id': event.id, 'name': 'Myself'})
registration.write({'name': 'Myself2'})
diff --git a/addons/event_sale/tests/test_event_internals.py b/addons/event_sale/tests/test_event_internals.py
index d70911b1524..0f3a7ae4d08 100644
--- a/addons/event_sale/tests/test_event_internals.py
+++ b/addons/event_sale/tests/test_event_internals.py
@@ -28,7 +28,6 @@ class TestEventData(TestEventSaleCommon):
'date_begin': FieldsDatetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': FieldsDatetime.to_string(datetime.today() + timedelta(days=15)),
})
- event._onchange_type()
self.assertEqual(event.event_ticket_ids, self.env['event.event.ticket'])
event_type.write({
@@ -43,7 +42,7 @@ class TestEventData(TestEventSaleCommon):
self.assertEqual(event_type.event_type_ticket_ids.description, self.event_product.description_sale)
# synchronize event
- event._onchange_type()
+ event.write({'event_type_id': event_type.id})
self.assertEqual(event.event_ticket_ids.name, event.event_type_id.event_type_ticket_ids.name)
self.assertEqual(event.event_ticket_ids.seats_availability, 'limited')
self.assertEqual(event.event_ticket_ids.seats_max, 5)
diff --git a/addons/website_event/models/event_event.py b/addons/website_event/models/event_event.py
index 472a60f802a..e67d6da0ce6 100644
--- a/addons/website_event/models/event_event.py
+++ b/addons/website_event/models/event_event.py
@@ -33,9 +33,10 @@ class Event(models.Model):
# website
website_published = fields.Boolean(tracking=True)
website_menu = fields.Boolean(
- 'Dedicated Menu', copy=False,
+ string='Dedicated Menu', copy=False,
+ compute='_compute_from_event_type', readonly=False, store=True,
help="Creates menus Introduction, Location and Register on the page "
- " of the event on the website.")
+ "of the event on the website.")
menu_id = fields.Many2one('website.menu', 'Event Menu', copy=False)
def _compute_is_participating(self):
@@ -55,11 +56,17 @@ class Event(models.Model):
if event.id: # avoid to perform a slug on a not yet saved record in case of an onchange.
event.website_url = '/event/%s' % slug(event)
- @api.onchange('event_type_id')
- def _onchange_type(self):
- super(Event, self)._onchange_type()
- if self.event_type_id:
- self.website_menu = self.event_type_id.website_menu
+ @api.depends('event_type_id')
+ def _compute_from_event_type(self):
+ """ Also ensure a value for website_menu as it is a trigger notably for
+ track related menus. """
+ super(Event, self)._compute_from_event_type()
+ for event in self:
+ if not event.event_type_id:
+ if not event.website_menu:
+ event.website_menu = False
+ elif event.event_type_id:
+ event.website_menu = event.event_type_id.website_menu
@api.model
def create(self, vals):
diff --git a/addons/website_event_questions/models/event_event.py b/addons/website_event_questions/models/event_event.py
index 53e1cfc0533..3a7984a30a0 100644
--- a/addons/website_event_questions/models/event_event.py
+++ b/addons/website_event_questions/models/event_event.py
@@ -17,21 +17,24 @@ class EventEvent(models.Model):
""" Override Event model to add optional questions when buying tickets. """
_inherit = 'event.event'
- question_ids = fields.One2many('event.question', 'event_id', 'Questions', copy=True)
+ question_ids = fields.One2many(
+ 'event.question', 'event_id', 'Questions', copy=True,
+ compute='_compute_from_event_type', readonly=False, store=True)
general_question_ids = fields.One2many('event.question', 'event_id', 'General Questions',
domain=[('once_per_order', '=', True)])
specific_question_ids = fields.One2many('event.question', 'event_id', 'Specific Questions',
domain=[('once_per_order', '=', False)])
- @api.onchange('event_type_id')
- def _onchange_type(self):
- super(EventEvent, self)._onchange_type()
- if self.event_type_id.use_questions and self.event_type_id.question_ids:
- self.question_ids = [(5, 0, 0)] + [
- (0, 0, {
- 'title': question.title,
- 'sequence': question.sequence,
- 'once_per_order': question.once_per_order,
- })
- for question in self.event_type_id.question_ids
- ]
+ @api.depends('event_type_id')
+ def _compute_from_event_type(self):
+ super(EventEvent, self)._compute_from_event_type()
+ for event in self:
+ if event.event_type_id.use_questions and event.event_type_id.question_ids:
+ event.question_ids = [(5, 0, 0)] + [
+ (0, 0, {
+ 'title': question.title,
+ 'sequence': question.sequence,
+ 'once_per_order': question.once_per_order,
+ })
+ for question in event.event_type_id.question_ids
+ ]
diff --git a/addons/website_event_questions/tests/test_event_internals.py b/addons/website_event_questions/tests/test_event_internals.py
index aedaf148fc9..d3494cae49c 100644
--- a/addons/website_event_questions/tests/test_event_internals.py
+++ b/addons/website_event_questions/tests/test_event_internals.py
@@ -22,7 +22,7 @@ class TestEventData(TestEventQuestionCommon):
'date_begin': FieldsDatetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': FieldsDatetime.to_string(datetime.today() + timedelta(days=15)),
})
- event._onchange_type()
+
self.assertEqual(event.specific_question_ids.title, 'Question1')
self.assertEqual(
set(event.specific_question_ids.mapped('answer_ids.name')),
diff --git a/addons/website_event_sale/tests/test_frontend_buy_tickets.py b/addons/website_event_sale/tests/test_frontend_buy_tickets.py
index e4698895587..a64dca5d4ad 100644
--- a/addons/website_event_sale/tests/test_frontend_buy_tickets.py
+++ b/addons/website_event_sale/tests/test_frontend_buy_tickets.py
@@ -4,6 +4,7 @@
import odoo.tests
from datetime import timedelta
+
from odoo.addons.base.tests.common import HttpCaseWithUserDemo
from odoo.fields import Datetime
@@ -16,8 +17,8 @@ class TestUi(HttpCaseWithUserDemo):
self.event_2 = self.env['event.event'].create({
'name': 'Conference for Architects TEST',
'user_id': self.env.ref('base.user_admin').id,
- 'date_begin': (Datetime.today()+ timedelta(days=5)).strftime('%Y-%m-%d 07:00:00'),
- 'date_end': (Datetime.today()+ timedelta(days=5)).strftime('%Y-%m-%d 16:30:00'),
+ 'date_begin': (Datetime.today() + timedelta(days=5)).strftime('%Y-%m-%d 07:00:00'),
+ 'date_end': (Datetime.today() + timedelta(days=5)).strftime('%Y-%m-%d 16:30:00'),
})
self.env['event.event.ticket'].create([{
@@ -35,6 +36,9 @@ class TestUi(HttpCaseWithUserDemo):
'price': 1500.0,
}])
+ # flush event to ensure having tickets available in the tests
+ self.event_2.flush()
+
(self.env.ref('base.partner_admin') + self.partner_demo).write({
'street': '215 Vine St',
'city': 'Scranton',