From b0845c0f2b48d6c7029a34ae50fc95876630e7ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 19 Aug 2020 09:55:26 +0000 Subject: [PATCH] [REM] website_event_online: merge into website_event PURPOSE Clean organization and models linked to Event Online feature introduced in semi stable saas-13.3 at odoo/odoo@981f95bbf46658eda9f2d33751b9310cc67d86aa and odoo/enterprise@14722028ae0773c3710ea48ce48ff44703e83b5a Also clean website event menu not being available in website event but only in website event track, which implies some extra-code to manage it. In short: merge website_event_online in website_event, website_event_track _(online/session) in website_event_track. RATIONALE _online modules have been added to extend content of website_event and website_event_track without having any impact on those module. First step of cleaning is to move this content directly in base module. track_session module is mainly a rewrite of track module. Second step of cleaning is to move its content directly in website_event_track. SPECIFICATIONS Move remaining content of website event online to website event. Update dependencies accordingly. LINKS Task ID-2319779 COM odoo/odoo#56067 ENT odoo/enterprise#12520 UPG odoo/upgrade#1654 --- addons/test_event_full/__manifest__.py | 1 - addons/test_event_full/tests/common.py | 2 +- addons/website_event/__manifest__.py | 6 +- addons/website_event/controllers/main.py | 23 ++++- addons/website_event/data/event_demo.xml | 2 + .../data/event_registration_demo.xml | 8 +- .../data/website_visitor_demo.xml | 2 +- addons/website_event/models/__init__.py | 3 + addons/website_event/models/event_event.py | 88 +++++++++++++++-- .../models/event_registration.py | 0 .../models/website_visitor.py | 0 .../website_event/security/event_security.xml | 11 +++ .../security/ir.model.access.csv | 1 + .../static/src/js/display_timer_widget.js | 2 +- .../static/src/js/register_toaster_widget.js | 2 +- .../src/scss/website_event_templates.scss | 0 addons/website_event/tests/__init__.py | 1 + addons/website_event/tests/common.py | 57 +++++++++++ .../tests/test_visitor_events.py | 0 addons/website_event/views/assets.xml | 3 + .../website_event/views/event_event_views.xml | 2 + .../views/event_registration_views.xml | 0 .../views/event_templates_list.xml | 10 +- .../views/event_templates_page.xml | 6 ++ .../event_templates_page_registration.xml | 1 + .../views/event_templates_widgets.xml | 26 +++++ .../views/website_visitor_views.xml | 2 +- addons/website_event_meet/__manifest__.py | 6 +- addons/website_event_online/__init__.py | 6 -- addons/website_event_online/__manifest__.py | 33 ------- .../controllers/__init__.py | 4 - .../controllers/event_registration.py | 31 ------ .../website_event_online/data/event_demo.xml | 9 -- .../website_event_online/models/__init__.py | 6 -- .../models/event_event.py | 95 ------------------- .../security/event_security.xml | 15 --- .../security/ir.model.access.csv | 2 - addons/website_event_online/tests/__init__.py | 5 - addons/website_event_online/tests/common.py | 68 ------------- addons/website_event_online/views/assets.xml | 14 --- .../views/event_event_views.xml | 18 ---- .../views/event_templates_event.xml | 54 ----------- .../views/event_templates_widgets.xml | 29 ------ .../__manifest__.py | 2 +- .../data/event_track_visitor_demo.xml | 4 +- .../tests/common.py | 2 +- .../views/event_event_views.xml | 2 +- .../views/website_visitor_views.xml | 6 +- .../data/quiz_demo.xml | 6 +- .../views/event_track_templates_page.xml | 2 +- 50 files changed, 249 insertions(+), 429 deletions(-) rename addons/{website_event_online => website_event}/data/event_registration_demo.xml (58%) rename addons/{website_event_online => website_event}/data/website_visitor_demo.xml (92%) rename addons/{website_event_online => website_event}/models/event_registration.py (100%) rename addons/{website_event_online => website_event}/models/website_visitor.py (100%) rename addons/{website_event_online => website_event}/static/src/js/display_timer_widget.js (98%) rename addons/{website_event_online => website_event}/static/src/js/register_toaster_widget.js (90%) rename addons/{website_event_online => website_event}/static/src/scss/website_event_templates.scss (100%) rename addons/{website_event_online => website_event}/tests/test_visitor_events.py (100%) rename addons/{website_event_online => website_event}/views/event_registration_views.xml (100%) rename addons/{website_event_online => website_event}/views/website_visitor_views.xml (96%) delete mode 100644 addons/website_event_online/__init__.py delete mode 100644 addons/website_event_online/__manifest__.py delete mode 100644 addons/website_event_online/controllers/__init__.py delete mode 100644 addons/website_event_online/controllers/event_registration.py delete mode 100644 addons/website_event_online/data/event_demo.xml delete mode 100644 addons/website_event_online/models/__init__.py delete mode 100644 addons/website_event_online/models/event_event.py delete mode 100644 addons/website_event_online/security/event_security.xml delete mode 100644 addons/website_event_online/security/ir.model.access.csv delete mode 100644 addons/website_event_online/tests/__init__.py delete mode 100644 addons/website_event_online/tests/common.py delete mode 100644 addons/website_event_online/views/assets.xml delete mode 100644 addons/website_event_online/views/event_event_views.xml delete mode 100644 addons/website_event_online/views/event_templates_event.xml delete mode 100644 addons/website_event_online/views/event_templates_widgets.xml diff --git a/addons/test_event_full/__manifest__.py b/addons/test_event_full/__manifest__.py index 4d6116280a9..363252c06a6 100644 --- a/addons/test_event_full/__manifest__.py +++ b/addons/test_event_full/__manifest__.py @@ -16,7 +16,6 @@ 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', 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 41fb932b683..a37438c0ed2 100644 --- a/addons/website_event/__manifest__.py +++ b/addons/website_event/__manifest__.py @@ -27,15 +27,19 @@ 'views/event_templates_widgets.xml', 'views/website_templates.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/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 f49b644b04f..cce22a56c9e 100644 --- a/addons/website_event/models/__init__.py +++ b/addons/website_event/models/__init__.py @@ -1,7 +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 7cf5f4e6b05..162cdf8cd55 100644 --- a/addons/website_event/models/event_event.py +++ b/addons/website_event/models/event_event.py @@ -4,8 +4,11 @@ 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?' @@ -36,6 +39,9 @@ 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, @@ -43,16 +49,58 @@ class Event(models.Model): 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) + """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: - self.is_participating = False + 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 + + for event in self: + event.is_participating = event in events @api.depends('event_type_id') def _compute_website_menu(self): @@ -75,6 +123,28 @@ class Event(models.Model): elif not event.website_menu: event.community_menu = False + @api.depends('website_menu') + def _compute_menu_register_cta(self): + for event in self: + event.menu_register_cta = event.website_menu + + @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() @@ -82,6 +152,10 @@ 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) + # ------------------------------------------------------------ + # CRUD + # ------------------------------------------------------------ + @api.model def create(self, vals): res = super(Event, self).create(vals) 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_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 e865d4a1581..49125082909 100644 --- a/addons/website_event/security/ir.model.access.csv +++ b/addons/website_event/security/ir.model.access.csv @@ -8,3 +8,4 @@ access_event_category_public,event.tag.category.public,event.model_event_tag_cat 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..8b447777d39 100644 --- a/addons/website_event/tests/common.py +++ b/addons/website_event/tests/common.py @@ -1,8 +1,52 @@ # -*- 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_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_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_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_main_dt.stop) + cls.addClassCleanup(cls.event_date.stop) + cls.addClassCleanup(cls.wevent_main_date.stop) class TestWebsiteEventCommon(TestEventCommon): @@ -43,3 +87,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_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 @@