diff options
| author | Thibault Delavallée <tde@odoo.com> | 2020-07-01 13:13:36 +0000 |
|---|---|---|
| committer | Thibault Delavallée <tde@odoo.com> | 2020-07-31 18:05:12 +0000 |
| commit | 917ad9a9a9f74e36c00ad2bc0d31b588b9afe0c8 (patch) | |
| tree | 87a2b5f1cadfb26cc9604bb3b898104e258affcd /addons/website_event | |
| parent | d5840a90936014d7ec62af936c0fef97505cb669 (diff) | |
[REF] website_event(_track): better support menu management from frontend
RATIONALE
Events are sometimes held online, gathering a community. In this merge we
improve Event application to better support full-online events with improved
tracks, wishlists, chat rooms, ...
PURPOSE
New and improved pages are about to land for online event. However current
menus and pages management is hard to tweak, especially when dealing with
the stable policy of 13.3 .
SPECIFICATIONS
Refactor and improve code about event menu management. Purpose is to
ease inheritance and be able to add menus and pages with less custom code
in sub modules.
Refactor some code, notably
* code dealing with menus to activate and de-activate that is duplicated
for each kind of menu;
* allow to give a menu_type through inheritance in create_menu notably to
support website.event.menu model available in Track app and unfortunately
not in website_event;
* make a somehow generic way of getting fields dealing with menu items
through simple inheritance;
* support sequence to allow ordering of menu entries by propagating the
sequence to website menus;
Behavior in website_event and website_event_track should be the same. Behavior
will be tweaked in other modules through inheritance..
Improve behavior when removing frontend menus
* correctly fetch views (for Introduction / Location) and try to unlink them
to avoid bloating the db;
* update boolean menu fields according to website menu management. Removing
a menu from frontend should be reflected on boolean fields of event;
LINKS
PR #55260
Task ID-2310491 (Event Online Preparation 5)
Part of Task ID-2252655 (Main Online Event task)
Part of Task ID-2283796 (Event B2Basics / Registration Flow)
Co-Authored-By: Aurélien Warnon <awa@odoo.com>
Co-Authored-By: David Beguin <dbe@odoo.com>
Co-Authored-By: Thibault Delavallée <tde@odoo.com>
Diffstat (limited to 'addons/website_event')
| -rw-r--r-- | addons/website_event/i18n/website_event.pot | 14 | ||||
| -rw-r--r-- | addons/website_event/models/event_event.py | 95 | ||||
| -rw-r--r-- | addons/website_event/tests/common.py | 34 | ||||
| -rw-r--r-- | addons/website_event/tests/test_event_internals.py | 17 |
4 files changed, 133 insertions, 27 deletions
diff --git a/addons/website_event/i18n/website_event.pot b/addons/website_event/i18n/website_event.pot index fc88fec0533..6a35067dfc1 100644 --- a/addons/website_event/i18n/website_event.pot +++ b/addons/website_event/i18n/website_event.pot @@ -335,11 +335,6 @@ msgid "Date & Time" msgstr "" #. module: website_event -#: model:ir.model.fields,field_description:website_event.field_event_event__website_menu -msgid "Dedicated Menu" -msgstr "" - -#. module: website_event #: model:ir.model.fields,field_description:website_event.field_event_type__website_menu msgid "Display a dedicated menu on Website" msgstr "" @@ -471,6 +466,8 @@ msgstr "" #. module: website_event #: code:addons/website_event/models/event_event.py:0 +#: code:addons/website_event/models/website_menu.py:0 +#: model_terms:ir.ui.view,arch_db:website_event.template_intro #, python-format msgid "Introduction" msgstr "" @@ -487,6 +484,7 @@ msgstr "" #. module: website_event #: code:addons/website_event/models/event_event.py:0 +#: code:addons/website_event/models/website_menu.py:0 #: model_terms:ir.ui.view,arch_db:website_event.event_description_full #, python-format msgid "Location" @@ -738,6 +736,12 @@ msgid "Website Home" msgstr "" #. module: website_event +#: model:ir.model,name:website_event.model_website_menu +#: model:ir.model.fields,field_description:website_event.field_event_event__website_menu +msgid "Website Menu" +msgstr "" + +#. module: website_event #. openerp-web #: code:addons/website_event/static/src/js/tours/event_tour.js:0 #, python-format diff --git a/addons/website_event/models/event_event.py b/addons/website_event/models/event_event.py index 41b4ff8bd05..c933ec38abf 100644 --- a/addons/website_event/models/event_event.py +++ b/addons/website_event/models/event_event.py @@ -33,8 +33,8 @@ class Event(models.Model): # website website_published = fields.Boolean(tracking=True) website_menu = fields.Boolean( - string='Dedicated Menu', - compute='_compute_from_event_type', readonly=False, store=True, + string='Website Menu', + compute='_compute_website_menu', readonly=False, store=True, 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) @@ -57,15 +57,14 @@ class Event(models.Model): event.website_url = '/event/%s' % slug(event) @api.depends('event_type_id') - def _compute_from_event_type(self): + def _compute_website_menu(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 and not event.website_menu: - event.website_menu = False - elif event.event_type_id: + if event.event_type_id and event.event_type_id != event._origin.event_type_id: event.website_menu = event.event_type_id.website_menu + elif not event.website_menu: + event.website_menu = False @api.model def create(self, vals): @@ -74,12 +73,10 @@ class Event(models.Model): return res def write(self, vals): - menu_activated = self.filtered(lambda event: event.website_menu) - menu_deactivated = self.filtered(lambda event: not event.website_menu) + menus_state_by_field = self._split_menus_state_by_field() res = super(Event, self).write(vals) - menu_to_deactivate = menu_activated.filtered(lambda event: not event.website_menu) - menu_to_activate = menu_deactivated.filtered(lambda event: event.website_menu) - (menu_to_activate | menu_to_deactivate)._update_website_menus() + menus_update_by_field = self._get_menus_update_by_field(menus_state_by_field) + self._update_website_menus(menus_update_by_field=menus_update_by_field) return res # ------------------------------------------------------------ @@ -89,9 +86,58 @@ class Event(models.Model): def toggle_website_menu(self, val): self.website_menu = val + def _get_menu_update_fields(self): + """" Return a list of fields triggering a split of menu to activate / + menu to de-activate. Due to saas-13.3 improvement of menu management + this is done using side-methods to ease inheritance. + + :return list: list of fields, each of which triggering a menu update + like website_menu, website_track, ... """ + return ['website_menu'] + + def _split_menus_state_by_field(self): + """ For each field linked to a menu, get the set of events having this + menu activated and de-activated. Purpose is to find those whose value + changed and update the underlying menus. + + :return dict: key = name of field triggering a website menu update, get { + 'activated': subset of self having its menu currently set to True + 'deactivated': subset of self having its menu currently set to False + } """ + menus_state_by_field = dict() + for fname in self._get_menu_update_fields(): + activated = self.filtered(lambda event: event[fname]) + menus_state_by_field[fname] = { + 'activated': activated, + 'deactivated': self - activated, + } + return menus_state_by_field + + def _get_menus_update_by_field(self, menus_state_by_field): + """ For each field linked to a menu, get the set of events requiring + this menu to be activated or de-activated based on previous recorded + value. + + :return dict: key = name of field triggering a website menu update, get { + 'activated': subset of self having its menu toggled to True + 'deactivated': subset of self having its menu toggled to False + } """ + menus_update_by_field = dict() + for fname in self._get_menu_update_fields(): + menus_update_by_field[fname] = self.env['event.event'] + menus_update_by_field[fname] |= menus_state_by_field[fname]['activated'].filtered(lambda event: not event[fname]) + 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): """ Method returning menu entries to display on the website view of the - event, possibly depending on some options in inheriting modules. """ + event, possibly depending on some options in inheriting modules. + + Each menu entry is a tuple containing : + * 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); + """ self.ensure_one() return [ (_('Introduction'), False, 'website_event.template_intro'), @@ -99,7 +145,10 @@ class Event(models.Model): (_('Register'), '/event/%s/register' % slug(self), False), ] - def _update_website_menus(self): + def _update_website_menus(self, menus_update_by_field=None): + """ Synchronize event configuration and its menu entries for frontend. + + :param menus_update_by_field: see ``_get_menus_update_by_field``""" for event in self: if event.menu_id and not event.website_menu: event.menu_id.unlink() @@ -109,19 +158,27 @@ class Event(models.Model): for sequence, (name, url, xml_id) in enumerate(event._get_menu_entries()): event._create_menu(sequence, name, url, xml_id) - def _create_menu(self, sequence, name, url, xml_id): + 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 + should be a valid route. If xml_id: create a new page, take its url back + thanks to new_page of website, then link it to a menu. Template is + duplicated and linked to a new url, meaning each menu will have its own + copy of the template. + + :param menu_type: type of menu. Mainly used for inheritance purpose + allowing more fine-grain tuning of menus. """ if not url: self.env['ir.ui.view'].with_context(_force_unlink=True).search([('name', '=', name + ' ' + self.name)]).unlink() - newpath = self.env['website'].sudo().new_page(name + ' ' + self.name, template=xml_id, ispage=False)['url'] - url = "/event/" + slug(self) + "/page/" + newpath[1:] - menu = self.env['website.menu'].sudo().create({ + page_result = self.env['website'].sudo().new_page(name + ' ' + self.name, template=xml_id, ispage=False) + url = "/event/" + slug(self) + "/page" + page_result['url'] # url contains starting "/" + website_menu = self.env['website.menu'].sudo().create({ 'name': name, 'url': url, 'parent_id': self.menu_id.id, 'sequence': sequence, 'website_id': self.website_id.id, }) - return menu + return website_menu # ------------------------------------------------------------ # TOOLS diff --git a/addons/website_event/tests/common.py b/addons/website_event/tests/common.py index b4bd532ab04..333a2ed4789 100644 --- a/addons/website_event/tests/common.py +++ b/addons/website_event/tests/common.py @@ -2,16 +2,44 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.addons.event.tests.common import TestEventCommon +from odoo.addons.mail.tests.common import mail_new_test_user class TestWebsiteEventCommon(TestEventCommon): + @classmethod + def setUpClass(cls): + super(TestWebsiteEventCommon, cls).setUpClass() + + cls.company_main = cls.env.user.company_id + cls.user_event_web_manager = mail_new_test_user( + cls.env, login='user_event_web_manager', + name='Martin Sales Manager', email='crm_manager@test.example.com', + company_id=cls.company_main.id, + notification_type='inbox', + groups='event.group_event_manager,website.group_website_designer', + ) + def _get_menus(self): return set(['Introduction', 'Location', 'Register']) - def _assert_website_menus(self, event): + def _assert_website_menus(self, event, menu_entries=None): self.assertTrue(event.menu_id) + if menu_entries is None: + menu_entries = self._get_menus() + menus = self.env['website.menu'].search([('parent_id', '=', event.menu_id.id)]) - self.assertEqual(len(menus), len(self._get_menus())) - self.assertEqual(set(menus.mapped('name')), self._get_menus()) + self.assertEqual(len(menus), len(menu_entries)) + self.assertEqual(set(menus.mapped('name')), menu_entries) + + for page_specific in ['Introduction', 'Location']: + view = self.env['ir.ui.view'].search( + [('name', '=', page_specific + ' ' + event.name)] + ) + if page_specific in menu_entries: + self.assertTrue(bool(view)) + # TDE FIXME: page deletion not done in 13.3 for Introduction/Location, difficult to fix + # without website.event.menu model (or crappy code based on name) + # else: + # self.assertFalse(bool(view)) diff --git a/addons/website_event/tests/test_event_internals.py b/addons/website_event/tests/test_event_internals.py index 83ff4901df8..9e99815fd67 100644 --- a/addons/website_event/tests/test_event_internals.py +++ b/addons/website_event/tests/test_event_internals.py @@ -20,6 +20,23 @@ class TestEventWebsite(TestWebsiteEventCommon): }) self._assert_website_menus(event) + @users('user_event_web_manager') + def test_menu_management_frontend(self): + event = self.env['event.event'].create({ + 'name': 'TestEvent', + '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, + }) + self.assertTrue(event.website_menu) + self._assert_website_menus(event) + + introduction_menu = event.menu_id.child_id.filtered(lambda menu: menu.name == 'Introduction') + introduction_menu.unlink() + + self.assertTrue(event.website_menu) + self._assert_website_menus(event, set(['Location', 'Register'])) + @users('user_eventmanager') def test_menu_update(self): event = self.env['event.event'].browse(self.event_0.id) |
