diff --git a/addons/event/__manifest__.py b/addons/event/__manifest__.py
index 5712bafd0d2..566a41f036f 100644
--- a/addons/event/__manifest__.py
+++ b/addons/event/__manifest__.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
{
'name': 'Events Organization',
- 'version': '1.2',
+ 'version': '1.3',
'website': 'https://www.odoo.com/page/events',
'category': 'Marketing/Events',
'summary': 'Trainings, Conferences, Meetings, Exhibitions, Registrations',
diff --git a/addons/event/data/event_demo_misc.xml b/addons/event/data/event_demo_misc.xml
index cbb647d8041..a87cce5d7bb 100644
--- a/addons/event/data/event_demo_misc.xml
+++ b/addons/event/data/event_demo_misc.xml
@@ -42,51 +42,60 @@
5-10
1
+ 1
10-14
2
+ 2
15-18
3
+ 3
18+
4
+ 4
Culture
10
+ 5
Music
11
+ 6
Sport
12
+ 7
Online
20
+ 8
Conference
21
+ 9
diff --git a/addons/event/models/event_tag.py b/addons/event/models/event_tag.py
index a4dcad1a5b3..dd097c333a7 100644
--- a/addons/event/models/event_tag.py
+++ b/addons/event/models/event_tag.py
@@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo import _, api, fields, models
+from random import randint
+
+from odoo import api, fields, models
class EventTagCategory(models.Model):
@@ -18,9 +20,15 @@ class EventTag(models.Model):
_description = "Event Tag"
_order = "sequence"
+ def _default_color(self):
+ return randint(1, 11)
+
name = fields.Char("Name", required=True, translate=True)
sequence = fields.Integer('Sequence', default=0)
category_id = fields.Many2one("event.tag.category", string="Category", required=True, ondelete='cascade')
+ color = fields.Integer(
+ string='Color Index', default=lambda self: self._default_color(),
+ help='Tag color. No color means no display in kanban or front-end, to distinguish internal tags from public categorization tags.')
def name_get(self):
return [(tag.id, "%s: %s" % (tag.category_id.name, tag.name)) for tag in self]
diff --git a/addons/event/models/res_config_settings.py b/addons/event/models/res_config_settings.py
index 69201cdbd2d..15af322830c 100644
--- a/addons/event/models/res_config_settings.py
+++ b/addons/event/models/res_config_settings.py
@@ -6,7 +6,11 @@ class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
module_event_sale = fields.Boolean("Tickets")
+ module_website_event_meet = fields.Boolean("Discussion Rooms")
module_website_event_track = fields.Boolean("Tracks and Agenda")
+ module_website_event_track_live = fields.Boolean("Live Mode")
+ module_website_event_track_quiz = fields.Boolean("Quiz on Tracks")
+ module_website_event_track_exhibitor = fields.Boolean("Advanced Sponsors")
module_website_event_questions = fields.Boolean("Registration Survey")
module_event_barcode = fields.Boolean("Barcode")
module_website_event_sale = fields.Boolean("Online Ticketing")
diff --git a/addons/event/views/event_tag_views.xml b/addons/event/views/event_tag_views.xml
index 10c94b0e82c..a1fe03843fd 100644
--- a/addons/event/views/event_tag_views.xml
+++ b/addons/event/views/event_tag_views.xml
@@ -9,7 +9,7 @@
-
+
@@ -28,6 +28,7 @@
+
@@ -51,6 +52,7 @@
+
@@ -64,6 +66,7 @@
+
diff --git a/addons/event/views/event_views.xml b/addons/event/views/event_views.xml
index faa081e643c..f3029824812 100644
--- a/addons/event/views/event_views.xml
+++ b/addons/event/views/event_views.xml
@@ -78,7 +78,7 @@
@@ -232,7 +232,7 @@
-
+
diff --git a/addons/event/views/res_config_settings_views.xml b/addons/event/views/res_config_settings_views.xml
index 8636b17efa3..9e70837b7a3 100644
--- a/addons/event/views/res_config_settings_views.xml
+++ b/addons/event/views/res_config_settings_views.xml
@@ -22,6 +22,44 @@
Manage & publish a schedule with tracks
+
+
+
+
+ Youtube support, Chat
+
+
+
+
+
+
+ Quizzes, leaderboard
+
+
+
+
+
+
+
+
+
+
+
+
+ Integrate discussion rooms
+
+
+
+
+
+
+
+
+
+
+ Chat, advanced exhibitors
+
+
diff --git a/addons/im_livechat/static/src/legacy/public_livechat.js b/addons/im_livechat/static/src/legacy/public_livechat.js
index 5a29d6e667f..4f14fbb06f7 100644
--- a/addons/im_livechat/static/src/legacy/public_livechat.js
+++ b/addons/im_livechat/static/src/legacy/public_livechat.js
@@ -111,7 +111,7 @@ var LivechatButton = Widget.extend({
this.$el.css('color', this.options.button_text_color);
}
- // If website_event_track_online installed, put the livechat banner above the PWA banner.
+ // If website_event_track installed, put the livechat banner above the PWA banner.
var pwaBannerHeight = $('.o_pwa_install_banner').outerHeight(true);
if (pwaBannerHeight) {
this.$el.css('bottom', pwaBannerHeight + 'px');
diff --git a/addons/test_event_full/__manifest__.py b/addons/test_event_full/__manifest__.py
index 4d6116280a9..8423fc06d7f 100644
--- a/addons/test_event_full/__manifest__.py
+++ b/addons/test_event_full/__manifest__.py
@@ -16,14 +16,11 @@ automatic lead generation, full Online support, ...
'event_sale',
'website_event_crm_questions',
'website_event_questions',
- 'website_event_online',
'website_event_questions',
'website_event_meet',
'website_event_sale',
'website_event_track',
- 'website_event_track_online',
'website_event_track_exhibitor',
- 'website_event_track_session',
'website_event_track_live',
'website_event_track_quiz',
],
diff --git a/addons/test_event_full/tests/common.py b/addons/test_event_full/tests/common.py
index 1e06d1be41c..c93396d8255 100644
--- a/addons/test_event_full/tests/common.py
+++ b/addons/test_event_full/tests/common.py
@@ -7,7 +7,7 @@ from odoo.addons.base.tests.common import HttpCaseWithUserDemo, HttpCaseWithUser
from odoo.addons.event_crm.tests.common import TestEventCrmCommon
from odoo.addons.sales_team.tests.common import TestSalesCommon
from odoo.addons.website.tests.test_website_visitor import MockVisitor
-from odoo.addons.website_event_online.tests.common import EventDtPatcher
+from odoo.addons.website_event.tests.common import EventDtPatcher
class TestEventFullCommon(TestEventCrmCommon, TestSalesCommon, EventDtPatcher, MockVisitor):
diff --git a/addons/website_event/__manifest__.py b/addons/website_event/__manifest__.py
index db44af018fd..a37438c0ed2 100644
--- a/addons/website_event/__manifest__.py
+++ b/addons/website_event/__manifest__.py
@@ -1,29 +1,45 @@
# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'Events',
+ 'version': '1.1',
'category': 'Marketing/Events',
'sequence': 140,
'summary': 'Publish events, sell tickets',
'website': 'https://www.odoo.com/page/events',
'description': "",
- 'depends': ['website', 'website_partner', 'website_mail', 'event'],
+ 'depends': [
+ 'event',
+ 'website',
+ 'website_partner',
+ 'website_mail',
+ ],
'data': [
'data/event_data.xml',
'views/assets.xml',
'views/res_config_settings_views.xml',
'views/event_snippets.xml',
- 'views/event_templates.xml',
- 'views/event_templates_misc_pages.xml',
- 'views/event_templates_registration.xml',
+ 'views/event_templates_list.xml',
+ 'views/event_templates_page.xml',
+ 'views/event_templates_page_registration.xml',
+ 'views/event_templates_page_misc.xml',
+ 'views/event_templates_widgets.xml',
'views/website_templates.xml',
- 'views/event_views.xml',
+ 'views/event_event_views.xml',
+ 'views/event_registration_views.xml',
+ 'views/event_type_views.xml',
+ 'views/website_event_menu_views.xml',
+ 'views/website_visitor_views.xml',
+ 'views/event_menus.xml',
'security/ir.model.access.csv',
'security/event_security.xml',
],
'demo': [
'data/res_partner_demo.xml',
- 'data/event_demo.xml'
+ 'data/website_visitor_demo.xml',
+ 'data/event_demo.xml',
+ 'data/event_registration_demo.xml',
],
'application': True,
}
diff --git a/addons/website_event/controllers/__init__.py b/addons/website_event/controllers/__init__.py
index 65a8c12013d..88cf7794fab 100644
--- a/addons/website_event/controllers/__init__.py
+++ b/addons/website_event/controllers/__init__.py
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
from . import main
+from . import community
diff --git a/addons/website_event_track_online/controllers/community.py b/addons/website_event/controllers/community.py
similarity index 72%
rename from addons/website_event_track_online/controllers/community.py
rename to addons/website_event/controllers/community.py
index 2720a94931f..57a8cc4694d 100644
--- a/addons/website_event_track_online/controllers/community.py
+++ b/addons/website_event/controllers/community.py
@@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo.addons.website_event.controllers.main import WebsiteEventController
-from odoo import fields, http, modules, tools
+from odoo import http
from odoo.http import request
-class WebsiteEventCommunityController(http.Controller):
+
+class EventCommunityController(http.Controller):
@http.route('/event//community', type="http", auth="public", website=True)
def community(self, event, lang=None, **kwargs):
diff --git a/addons/website_event/controllers/main.py b/addons/website_event/controllers/main.py
index 0665dce85bb..c003279c12b 100644
--- a/addons/website_event/controllers/main.py
+++ b/addons/website_event/controllers/main.py
@@ -345,13 +345,34 @@ class WebsiteEventController(http.Controller):
return list(registrations.values())
def _create_attendees_from_registration_post(self, event, registration_data):
+ """ Also try to set a visitor (from request) and
+ a partner (if visitor linked to a user for example). Purpose is to gather
+ as much informations as possible, notably to ease future communications.
+ Also try to update visitor informations based on registration info. """
+ visitor_sudo = request.env['website.visitor']._get_visitor_from_request(force_create=True)
+ visitor_sudo._update_visitor_last_visit()
+ visitor_values = {}
+
registrations_to_create = []
for registration_values in registration_data:
registration_values['event_id'] = event.id
- if not registration_values.get('partner_id'):
+ if not registration_values.get('partner_id') and visitor_sudo.partner_id:
+ registration_values['partner_id'] = visitor_sudo.partner_id.id
+ elif not registration_values.get('partner_id'):
registration_values['partner_id'] = request.env.user.partner_id.id
+
+ if visitor_sudo:
+ # registration may give a name to the visitor, yay
+ if registration_values.get('name') and not visitor_sudo.name and not visitor_values.get('name'):
+ visitor_values['name'] = registration_values['name']
+ # update registration based on visitor
+ registration_values['visitor_id'] = visitor_sudo.id
+
registrations_to_create.append(registration_values)
+ if visitor_values:
+ visitor_sudo.write(visitor_values)
+
return request.env['event.registration'].sudo().create(registrations_to_create)
@http.route(['''/event//registration/confirm'''], type='http', auth="public", methods=['POST'], website=True)
diff --git a/addons/website_event/data/event_demo.xml b/addons/website_event/data/event_demo.xml
index 85a46feb7a7..a894ec82128 100644
--- a/addons/website_event/data/event_demo.xml
+++ b/addons/website_event/data/event_demo.xml
@@ -41,6 +41,7 @@
+
The Great Reno Balloon Race is the world's largest free hot-air ballooning event.
{"background-image": "url('/website_event/static/src/img/event_cover_1.jpg')", "resize_class": "o_record_has_cover o_half_screen_height", "opacity": "0.4"}
@@ -151,6 +152,7 @@
+
Our newest collection will be revealed online! Interact with us on our live streams!
{"background-image": "url('/website_event/static/src/img/event_cover_7.jpg')", "resize_class": "o_record_has_cover o_half_screen_height", "opacity": "0.4"}
diff --git a/addons/website_event_online/data/event_registration_demo.xml b/addons/website_event/data/event_registration_demo.xml
similarity index 58%
rename from addons/website_event_online/data/event_registration_demo.xml
rename to addons/website_event/data/event_registration_demo.xml
index d89b4d1aabf..ff661e424a9 100644
--- a/addons/website_event_online/data/event_registration_demo.xml
+++ b/addons/website_event/data/event_registration_demo.xml
@@ -3,16 +3,16 @@
-
+
-
+
-
+
-
+
diff --git a/addons/website_event_online/data/website_visitor_demo.xml b/addons/website_event/data/website_visitor_demo.xml
similarity index 92%
rename from addons/website_event_online/data/website_visitor_demo.xml
rename to addons/website_event/data/website_visitor_demo.xml
index 174b1c17b68..8403ae7fb0b 100644
--- a/addons/website_event_online/data/website_visitor_demo.xml
+++ b/addons/website_event/data/website_visitor_demo.xml
@@ -18,7 +18,7 @@
Philipe J. Fry (old)
-
+
diff --git a/addons/website_event/models/__init__.py b/addons/website_event/models/__init__.py
index 67661173e03..cce22a56c9e 100644
--- a/addons/website_event/models/__init__.py
+++ b/addons/website_event/models/__init__.py
@@ -1,4 +1,10 @@
# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import event_event
+from . import event_registration
+from . import event_type
from . import website
+from . import website_event_menu
+from . import website_menu
+from . import website_visitor
diff --git a/addons/website_event/models/event_event.py b/addons/website_event/models/event_event.py
index 925aed32996..72f8096b5a1 100644
--- a/addons/website_event/models/event_event.py
+++ b/addons/website_event/models/event_event.py
@@ -1,25 +1,26 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-import werkzeug.urls
import json
+import werkzeug.urls
+
+from pytz import utc
from odoo import api, fields, models, _
from odoo.addons.http_routing.models.ir_http import slug
+from odoo.osv import expression
GOOGLE_CALENDAR_URL = 'https://www.google.com/calendar/render?'
-class EventType(models.Model):
- _name = 'event.type'
- _inherit = ['event.type']
-
- website_menu = fields.Boolean('Display a dedicated menu on Website')
-
-
class Event(models.Model):
_name = 'event.event'
- _inherit = ['event.event', 'website.seo.metadata', 'website.published.multi.mixin', 'website.cover_properties.mixin']
+ _inherit = [
+ 'event.event',
+ 'website.seo.metadata',
+ 'website.published.multi.mixin',
+ 'website.cover_properties.mixin'
+ ]
def _default_cover_properties(self):
res = super()._default_cover_properties()
@@ -38,23 +39,68 @@ class Event(models.Model):
help="Creates menus Introduction, Location and Register on the page "
"of the event on the website.")
menu_id = fields.Many2one('website.menu', 'Event Menu', copy=False)
+ menu_register_cta = fields.Boolean(
+ 'Add Register Button', compute='_compute_menu_register_cta',
+ readonly=False, store=True)
+ community_menu = fields.Boolean(
+ "Community Menu", compute="_compute_community_menu",
+ readonly=False, store=True,
+ help="Display community tab on website")
+ community_menu_ids = fields.One2many(
+ "website.event.menu", "event_id", string="Event Community Menus",
+ domain=[("menu_type", "=", "community")])
+ # live information
+ is_ongoing = fields.Boolean(
+ 'Is Ongoing', compute='_compute_time_data', search='_search_is_ongoing',
+ help="Whether event has begun")
+ is_done = fields.Boolean(
+ 'Is Done', compute='_compute_time_data',
+ help="Whether event is finished")
+ start_today = fields.Boolean(
+ 'Start Today', compute='_compute_time_data',
+ help="Whether event is going to start today if still not ongoing")
+ start_remaining = fields.Integer(
+ 'Remaining before start', compute='_compute_time_data',
+ help="Remaining time before event starts (minutes)")
def _compute_is_participating(self):
- # we don't allow public user to see participating label
- if self.env.user != self.env['website'].get_current_website().user_id:
- email = self.env.user.partner_id.email
- for event in self:
- domain = ['&', '|', ('email', '=', email), ('partner_id', '=', self.env.user.partner_id.id), ('event_id', '=', event.id)]
- event.is_participating = self.env['event.registration'].sudo().search_count(domain)
- else:
- self.is_participating = False
+ """Heuristic
+
+ * public, no visitor: not participating as we have no information;
+ * public and visitor: check visitor is linked to a registration. As
+ visitors are merged on the top parent, current visitor check is
+ sufficient even for successive visits;
+ * logged, no visitor: check partner is linked to a registration. Do
+ not check the email as it is not really secure;
+ * logged as visitor: check partner or visitor are linked to a
+ registration;
+ """
+ current_visitor = self.env['website.visitor']._get_visitor_from_request(force_create=False)
+ if self.env.user._is_public() and not current_visitor:
+ events = self.env['event.event']
+ elif self.env.user._is_public():
+ events = self.env['event.registration'].sudo().search([
+ ('event_id', 'in', self.ids),
+ ('visitor_id', '=', current_visitor.id),
+ ]).event_id
+ else:
+ if current_visitor:
+ domain = [
+ '|',
+ ('partner_id', '=', self.env.user.partner_id.id),
+ ('visitor_id', '=', current_visitor.id)
+ ]
+ else:
+ domain = [('partner_id', '=', self.env.user.partner_id.id)]
+ events = self.env['event.registration'].sudo().search(
+ expression.AND([
+ domain,
+ [('event_id', 'in', self.ids)]
+ ])
+ ).event_id
- @api.depends('name')
- def _compute_website_url(self):
- super(Event, self)._compute_website_url()
for event in self:
- 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)
+ event.is_participating = event in events
@api.depends('event_type_id')
def _compute_website_menu(self):
@@ -66,6 +112,56 @@ class Event(models.Model):
elif not event.website_menu:
event.website_menu = False
+ @api.depends("event_type_id", "website_menu", "community_menu")
+ def _compute_community_menu(self):
+ """ At type onchange: synchronize. At website_menu update: synchronize. """
+ for event in self:
+ if event.event_type_id and event.event_type_id != event._origin.event_type_id:
+ event.community_menu = event.event_type_id.community_menu
+ elif event.website_menu and event.website_menu != event._origin.website_menu or not event.community_menu:
+ event.community_menu = True
+ elif not event.website_menu:
+ event.community_menu = False
+
+ @api.depends("event_type_id", "website_menu")
+ def _compute_menu_register_cta(self):
+ """ At type onchange: synchronize. At website_menu update: synchronize. """
+ for event in self:
+ if event.event_type_id and event.event_type_id != event._origin.event_type_id:
+ event.menu_register_cta = event.event_type_id.menu_register_cta
+ elif event.website_menu and event.website_menu != event._origin.website_menu or not event.menu_register_cta:
+ event.menu_register_cta = True
+ elif not event.website_menu:
+ event.menu_register_cta = False
+
+ @api.depends('date_begin', 'date_end')
+ def _compute_time_data(self):
+ """ Compute start and remaining time. Do everything in UTC as we compute only
+ time deltas here. """
+ now_utc = utc.localize(fields.Datetime.now().replace(microsecond=0))
+ for event in self:
+ date_begin_utc = utc.localize(event.date_begin, is_dst=False)
+ date_end_utc = utc.localize(event.date_end, is_dst=False)
+ event.is_ongoing = date_begin_utc <= now_utc <= date_end_utc
+ event.is_done = now_utc > date_end_utc
+ event.start_today = date_begin_utc.date() == now_utc.date()
+ if date_begin_utc >= now_utc:
+ td = date_begin_utc - now_utc
+ event.start_remaining = int(td.total_seconds() / 60)
+ else:
+ event.start_remaining = 0
+
+ @api.depends('name')
+ def _compute_website_url(self):
+ super(Event, self)._compute_website_url()
+ for event in self:
+ 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)
+
+ # ------------------------------------------------------------
+ # CRUD
+ # ------------------------------------------------------------
+
@api.model
def create(self, vals):
res = super(Event, self).create(vals)
@@ -93,7 +189,10 @@ class Event(models.Model):
:return list: list of fields, each of which triggering a menu update
like website_menu, website_track, ... """
- return ['website_menu']
+ return ['website_menu', 'community_menu']
+
+ def _get_menu_type_field_matching(self):
+ return {'community': 'community_menu'}
def _split_menus_state_by_field(self):
""" For each field linked to a menu, get the set of events having this
@@ -137,7 +236,7 @@ class Event(models.Model):
menus_update_by_field[fname] |= menus_state_by_field[fname]['deactivated'].filtered(lambda event: event[fname])
return menus_update_by_field
- def _get_menu_entries(self):
+ def _get_website_menu_entries(self):
""" Method returning menu entries to display on the website view of the
event, possibly depending on some options in inheriting modules.
@@ -145,14 +244,22 @@ class Event(models.Model):
* name: menu item name
* url: if set, url to a route (do not use xml_id in that case);
* xml_id: template linked to the page (do not use url in that case);
+ * sequence: specific sequence of menu entry to be set on the menu;
+ * menu_type: type of menu entry (used in inheriting modules to ease
+ menu management; not used in this module in 13.3 due to technical
+ limitations);
"""
self.ensure_one()
return [
- (_('Introduction'), False, 'website_event.template_intro'),
- (_('Location'), False, 'website_event.template_location'),
- (_('Register'), '/event/%s/register' % slug(self), False),
+ (_('Introduction'), False, 'website_event.template_intro', 1, False),
+ (_('Location'), False, 'website_event.template_location', 50, False),
+ (_('Register'), '/event/%s/register' % slug(self), False, 100, False),
]
+ def _get_community_menu_entries(self):
+ self.ensure_one()
+ return [(_('Community'), '/event/%s/community' % slug(self), False, 80, 'community')]
+
def _update_website_menus(self, menus_update_by_field=None):
""" Synchronize event configuration and its menu entries for frontend.
@@ -163,8 +270,44 @@ class Event(models.Model):
elif event.website_menu and not event.menu_id:
root_menu = self.env['website.menu'].sudo().create({'name': event.name, 'website_id': event.website_id.id})
event.menu_id = root_menu
- for sequence, (name, url, xml_id) in enumerate(event._get_menu_entries()):
- event._create_menu(sequence, name, url, xml_id)
+ if event.website_menu and (not menus_update_by_field or event in menus_update_by_field.get('website_menu')):
+ for name, url, xml_id, menu_sequence, menu_type in event._get_website_menu_entries():
+ event._create_menu(menu_sequence, name, url, xml_id, menu_type=menu_type)
+ if event.menu_id and (not menus_update_by_field or event in menus_update_by_field.get('community_menu')):
+ event._update_website_menu_entry('community_menu', 'community_menu_ids', '_get_community_menu_entries')
+
+ def _update_website_menu_entry(self, fname_bool, fname_o2m, method_name):
+ """ Generic method to create menu entries based on a flag on event. This
+ method is a bit obscure, but is due to preparation of adding new menus
+ entries and pages for event in a stable version, leading to some constraints
+ while developing.
+
+ :param fname_bool: field name (e.g. website_track)
+ :param fname_o2m: o2m linking towards website.event.menu matching the
+ boolean fields (normally an entry ot website.event.menu with type matching
+ the boolean field name)
+ :param method_name: method returning menu entries information: url, sequence, ...
+ """
+ self.ensure_one()
+ new_menu = None
+
+ if self[fname_bool] and not self[fname_o2m]:
+ # menus not found but boolean True: get menus to create
+ for sequence, menu_data in enumerate(getattr(self, method_name)()):
+ # some modules have 4 data: name, url, xml_id, menu_type; however we
+ # plan to support sequence in future modules, so this hackish code is
+ # necessary to avoid crashing. Not nice, but stable target = meh.
+ if len(menu_data) == 4:
+ (name, url, xml_id, menu_type) = menu_data
+ menu_sequence = sequence
+ elif len(menu_data) == 5:
+ (name, url, xml_id, menu_sequence, menu_type) = menu_data
+ new_menu = self._create_menu(menu_sequence, name, url, xml_id, menu_type=menu_type)
+ elif not self[fname_bool]:
+ # will cascade delete to the website.event.menu
+ self[fname_o2m].mapped('menu_id').sudo().unlink()
+
+ return new_menu
def _create_menu(self, sequence, name, url, xml_id, menu_type=False):
""" If url: create a website menu. Menu leads directly to the URL that
@@ -186,6 +329,12 @@ class Event(models.Model):
'sequence': sequence,
'website_id': self.website_id.id,
})
+ if menu_type:
+ self.env['website.event.menu'].create({
+ 'menu_id': website_menu.id,
+ 'event_id': self.id,
+ 'menu_type': menu_type,
+ })
return website_menu
# ------------------------------------------------------------
diff --git a/addons/website_event_online/models/event_registration.py b/addons/website_event/models/event_registration.py
similarity index 100%
rename from addons/website_event_online/models/event_registration.py
rename to addons/website_event/models/event_registration.py
diff --git a/addons/website_event_track_online/models/event_type.py b/addons/website_event/models/event_type.py
similarity index 53%
rename from addons/website_event_track_online/models/event_type.py
rename to addons/website_event/models/event_type.py
index 9b2efc94af8..43acf03360b 100644
--- a/addons/website_event_track_online/models/event_type.py
+++ b/addons/website_event/models/event_type.py
@@ -5,14 +5,24 @@ from odoo import api, fields, models
class EventType(models.Model):
- _inherit = "event.type"
+ _name = 'event.type'
+ _inherit = ['event.type']
+ website_menu = fields.Boolean('Display a dedicated menu on Website')
community_menu = fields.Boolean(
"Community Menu", compute="_compute_community_menu",
readonly=False, store=True,
help="Display community tab on website")
+ menu_register_cta = fields.Boolean(
+ 'Add Register Button', compute='_compute_menu_register_cta',
+ readonly=False, store=True)
@api.depends('website_menu')
def _compute_community_menu(self):
for event_type in self:
event_type.community_menu = event_type.website_menu
+
+ @api.depends('website_menu')
+ def _compute_menu_register_cta(self):
+ for event_type in self:
+ event_type.menu_register_cta = event_type.website_menu
diff --git a/addons/website_event/models/website_event_menu.py b/addons/website_event/models/website_event_menu.py
new file mode 100644
index 00000000000..b19c7d8ca75
--- /dev/null
+++ b/addons/website_event/models/website_event_menu.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import fields, models
+
+
+class EventMenu(models.Model):
+ _name = "website.event.menu"
+ _description = "Website Event Menu"
+
+ menu_id = fields.Many2one('website.menu', string='Menu', ondelete='cascade')
+ event_id = fields.Many2one('event.event', string='Event', ondelete='cascade')
+ menu_type = fields.Selection([
+ ('community', 'Community Menu')], string="Menu Type",
+ ondelete={'community': 'cascade'}, required=True)
diff --git a/addons/website_event/models/website_menu.py b/addons/website_event/models/website_menu.py
new file mode 100644
index 00000000000..1b96cd8552c
--- /dev/null
+++ b/addons/website_event/models/website_menu.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models
+
+
+class WebsiteMenu(models.Model):
+ _inherit = "website.menu"
+
+ def unlink(self):
+ """ Override to synchronize event configuration fields with menu deletion.
+ This should be cleaned in upcoming versions. """
+ event_updates = {}
+ website_event_menus = self.env['website.event.menu'].search([('menu_id', 'in', self.ids)])
+ for event_menu in website_event_menus:
+ to_update = event_updates.setdefault(event_menu.event_id, list())
+ for menu_type, fname in event_menu.event_id._get_menu_type_field_matching().items():
+ if event_menu.menu_type == menu_type:
+ to_update.append(fname)
+
+ # call super that resumes the unlink of menus entries (including website event menus)
+ res = super(WebsiteMenu, self).unlink()
+
+ # update events
+ for event, to_update in event_updates.items():
+ if to_update:
+ event.write(dict((fname, False) for fname in to_update))
+
+ return res
diff --git a/addons/website_event_online/models/website_visitor.py b/addons/website_event/models/website_visitor.py
similarity index 100%
rename from addons/website_event_online/models/website_visitor.py
rename to addons/website_event/models/website_visitor.py
diff --git a/addons/website_event/security/event_security.xml b/addons/website_event/security/event_security.xml
index 857e758e9c0..1aabb8f3025 100644
--- a/addons/website_event/security/event_security.xml
+++ b/addons/website_event/security/event_security.xml
@@ -12,6 +12,17 @@
+
+ Event Tag: public/portal: color = published
+
+ ['&', ('color', '!=', False), ('color', '!=', 0)]
+
+
+
+
+
+
+
Event Ticket: public/portal: published read
diff --git a/addons/website_event/security/ir.model.access.csv b/addons/website_event/security/ir.model.access.csv
index 985c14e5190..49125082909 100644
--- a/addons/website_event/security/ir.model.access.csv
+++ b/addons/website_event/security/ir.model.access.csv
@@ -6,3 +6,6 @@ access_event_event_ticket_public,event.event.ticket.public,event.model_event_eve
access_event_event_ticket_portal,event.event.ticket.portal,event.model_event_event_ticket,base.group_portal,1,0,0,0
access_event_category_public,event.tag.category.public,event.model_event_tag_category,,1,0,0,0
access_event_tag_public,event.tag.public,event.model_event_tag,,1,0,0,0
+access_website_event_menu_public,website.event.menu,model_website_event_menu,,1,0,0,0
+access_website_event_menu_manager,website.event.menu,model_website_event_menu,event.group_event_manager,1,1,1,1
+website_visitor_access_event_user,website.visitor.access.event.user,model_website_visitor,event.group_event_user,1,1,0,0
diff --git a/addons/website_event_online/static/src/js/display_timer_widget.js b/addons/website_event/static/src/js/display_timer_widget.js
similarity index 98%
rename from addons/website_event_online/static/src/js/display_timer_widget.js
rename to addons/website_event/static/src/js/display_timer_widget.js
index 0ada123c3b0..5f61273661f 100644
--- a/addons/website_event_online/static/src/js/display_timer_widget.js
+++ b/addons/website_event/static/src/js/display_timer_widget.js
@@ -1,4 +1,4 @@
-odoo.define('website_event_online.display_timer_widget', function (require) {
+odoo.define('website_event.display_timer_widget', function (require) {
'use strict';
var core = require('web.core');
diff --git a/addons/website_event_online/static/src/js/register_toaster_widget.js b/addons/website_event/static/src/js/register_toaster_widget.js
similarity index 90%
rename from addons/website_event_online/static/src/js/register_toaster_widget.js
rename to addons/website_event/static/src/js/register_toaster_widget.js
index 83397e74c40..891f61554c7 100644
--- a/addons/website_event_online/static/src/js/register_toaster_widget.js
+++ b/addons/website_event/static/src/js/register_toaster_widget.js
@@ -1,4 +1,4 @@
-odoo.define('website_event_online.register_toaster_widget', function (require) {
+odoo.define('website_event.register_toaster_widget', function (require) {
'use strict';
let core = require('web.core');
diff --git a/addons/website_event_online/static/src/scss/website_event_templates.scss b/addons/website_event/static/src/scss/website_event_templates.scss
similarity index 100%
rename from addons/website_event_online/static/src/scss/website_event_templates.scss
rename to addons/website_event/static/src/scss/website_event_templates.scss
diff --git a/addons/website_event/tests/__init__.py b/addons/website_event/tests/__init__.py
index 41f5bb1157f..77fa25d467c 100644
--- a/addons/website_event/tests/__init__.py
+++ b/addons/website_event/tests/__init__.py
@@ -4,5 +4,6 @@
from . import common
from . import test_event_internals
from . import test_ui
+from . import test_visitor_events
from . import test_website_event
from . import test_website_event_access
diff --git a/addons/website_event/tests/common.py b/addons/website_event/tests/common.py
index 333a2ed4789..1dbf91c8e49 100644
--- a/addons/website_event/tests/common.py
+++ b/addons/website_event/tests/common.py
@@ -1,8 +1,59 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+from datetime import datetime, timedelta, time
+from unittest.mock import patch
+
from odoo.addons.event.tests.common import TestEventCommon
from odoo.addons.mail.tests.common import mail_new_test_user
+from odoo.fields import Datetime as FieldsDatetime, Date as FieldsDate
+from odoo.tests.common import SavepointCase
+
+
+class EventDtPatcher(SavepointCase):
+
+ @classmethod
+ def setUpClass(cls):
+ super(EventDtPatcher, cls).setUpClass()
+
+ cls.reference_now = datetime(2020, 7, 6, 10, 0, 0)
+ cls.reference_today = datetime(2020, 7, 6)
+
+ cls.event_dt = patch(
+ 'odoo.addons.event.models.event_event.fields.Datetime',
+ wraps=FieldsDatetime
+ )
+ cls.wevent_dt = patch(
+ 'odoo.addons.website_event.models.event_event.fields.Datetime',
+ wraps=FieldsDatetime
+ )
+ cls.wevent_main_dt = patch(
+ 'odoo.addons.website_event.controllers.main.fields.Datetime',
+ wraps=FieldsDatetime
+ )
+ cls.event_date = patch(
+ 'odoo.addons.event.models.event_event.fields.Date',
+ wraps=FieldsDate
+ )
+ cls.wevent_main_date = patch(
+ 'odoo.addons.website_event.controllers.main.fields.Date',
+ wraps=FieldsDate
+ )
+ cls.mock_event_dt = cls.event_dt.start()
+ cls.mock_wevent_dt = cls.wevent_dt.start()
+ cls.mock_wevent_main_dt = cls.wevent_main_dt.start()
+ cls.mock_event_date = cls.event_date.start()
+ cls.mock_wevent_main_date = cls.wevent_main_date.start()
+ cls.mock_event_dt.now.return_value = cls.reference_now
+ cls.mock_wevent_dt.now.return_value = cls.reference_now
+ cls.mock_wevent_main_dt.now.return_value = cls.reference_now
+ cls.mock_event_date.today.return_value = cls.reference_today
+ cls.mock_wevent_main_date.today.return_value = cls.reference_today
+ cls.addClassCleanup(cls.event_dt.stop)
+ cls.addClassCleanup(cls.wevent_dt.stop)
+ cls.addClassCleanup(cls.wevent_main_dt.stop)
+ cls.addClassCleanup(cls.event_date.stop)
+ cls.addClassCleanup(cls.wevent_main_date.stop)
class TestWebsiteEventCommon(TestEventCommon):
@@ -43,3 +94,16 @@ class TestWebsiteEventCommon(TestEventCommon):
# without website.event.menu model (or crappy code based on name)
# else:
# self.assertFalse(bool(view))
+
+
+class TestEventOnlineCommon(TestEventCommon, EventDtPatcher):
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestEventOnlineCommon, cls).setUpClass()
+
+ # event if 8-18 in Europe/Brussels (DST) (first day: begins at 9, last day: ends at 15)
+ cls.event_0.write({
+ 'date_begin': datetime.combine(cls.reference_now, time(7, 0)) - timedelta(days=1),
+ 'date_end': datetime.combine(cls.reference_now, time(13, 0)) + timedelta(days=1),
+ })
diff --git a/addons/website_event/tests/test_event_internals.py b/addons/website_event/tests/test_event_internals.py
index 9e99815fd67..9339da20e6a 100644
--- a/addons/website_event/tests/test_event_internals.py
+++ b/addons/website_event/tests/test_event_internals.py
@@ -17,6 +17,7 @@ class TestEventWebsite(TestWebsiteEventCommon):
'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)),
'website_menu': True,
+ 'community_menu': False,
})
self._assert_website_menus(event)
@@ -27,6 +28,7 @@ class TestEventWebsite(TestWebsiteEventCommon):
'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)),
'website_menu': True,
+ 'community_menu': False,
})
self.assertTrue(event.website_menu)
self._assert_website_menus(event)
diff --git a/addons/website_event_online/tests/test_visitor_events.py b/addons/website_event/tests/test_visitor_events.py
similarity index 100%
rename from addons/website_event_online/tests/test_visitor_events.py
rename to addons/website_event/tests/test_visitor_events.py
diff --git a/addons/website_event/views/assets.xml b/addons/website_event/views/assets.xml
index e19a829e3ff..cbf9e23a6bf 100644
--- a/addons/website_event/views/assets.xml
+++ b/addons/website_event/views/assets.xml
@@ -10,8 +10,11 @@
+
+
+
diff --git a/addons/website_event/views/event_views.xml b/addons/website_event/views/event_event_views.xml
similarity index 54%
rename from addons/website_event/views/event_views.xml
rename to addons/website_event/views/event_event_views.xml
index e78bee85014..f364ac129c6 100644
--- a/addons/website_event/views/event_views.xml
+++ b/addons/website_event/views/event_event_views.xml
@@ -1,31 +1,7 @@
-
- event.type.view.form.inherit.website
- event.type
-
-
-
-
-
-
-
-
-
-
-
- Check this option to have menus for your event on the
- website: registrations, schedule, map, ...
-
-
-
-
-
-
-
-
-
+
event.event.view.form.inherit.website
event.event
@@ -43,10 +19,20 @@
type="object"
string="Preview Badges"/>
+
+
+
+
+
+
+
+
+
+
-
+
event.event.view.list.inherit.website
event.event
diff --git a/addons/website_event/views/event_menus.xml b/addons/website_event/views/event_menus.xml
new file mode 100644
index 00000000000..623a223679b
--- /dev/null
+++ b/addons/website_event/views/event_menus.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/addons/website_event_online/views/event_registration_views.xml b/addons/website_event/views/event_registration_views.xml
similarity index 100%
rename from addons/website_event_online/views/event_registration_views.xml
rename to addons/website_event/views/event_registration_views.xml
diff --git a/addons/website_event/views/event_snippets.xml b/addons/website_event/views/event_snippets.xml
index 4407b19f7e3..15634348006 100644
--- a/addons/website_event/views/event_snippets.xml
+++ b/addons/website_event/views/event_snippets.xml
@@ -12,40 +12,6 @@
-
-
-
-
-
diff --git a/addons/website_event/views/event_templates.xml b/addons/website_event/views/event_templates_list.xml
similarity index 62%
rename from addons/website_event/views/event_templates.xml
rename to addons/website_event/views/event_templates_list.xml
index d2d5ce204a6..4ad91388abe 100644
--- a/addons/website_event/views/event_templates.xml
+++ b/addons/website_event/views/event_templates_list.xml
@@ -97,15 +97,16 @@
-
+