From 8d37126629e7aa2a99242a65d29fbaa8dbd9ea30 Mon Sep 17 00:00:00 2001 From: David Beguin Date: Thu, 25 Jun 2020 08:05:18 +0000 Subject: [PATCH] [IMP] website_event_track_online : add wishlist mechanism on event tracks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Allow visitors and logged users to wishlist tracks and link tracks to visitors. Purpose is to improve engagement and promote tracks before an event. SPECIFICATIONS: TRACK WISHLIST Add a link between visitors or partners, and tracks. This link is done in a new many2many relationship build on event.track.visitor new model. It is used to store the wishlist flag. That way even public users can wishlist a track using their visitor. At login, information is propagated to their partner. It means that wishlist are saved if customer logs in or registers. We also add a widget for frontend pages. It allows to toggle the wishlist flag on tracks. It is based on visitor and/or current user, leading to a complete flow even for anonymous people. We allow to set some tracks as "keynotes". Those are considered as wishlisted by default. In order to avoid storing too much information, we do not create an entry in the wishlist table for each attendee. We simply consider all event attendees to have wishlisted this track by default. In order to be able to mute a keynote, a blacklist mechanism is implemented. Using the same relationship table between visitors or partners and tracks, a flag is added that blacklists the track. Fields are added on visitor allowing to dynamically build a domain to find visitors that wishlisted a track (or did not blacklist list in case of default wishlist). This could be used for example to automatically contact attendees before a track, like what is done in enterprise counterpart of this merge. LINKS Community PR #53540 Enterprise PR odoo/enterprise#11384 Task ID-2252655 (Main Online Event task) Task ID-2283796 (Event B2Basics / Registration Flow Task ID-2284043 (Visitor-based track wishlist) Task ID-2283869 (Notify attendees by push) Co-Authored-By: Aurélien Warnon Co-Authored-By: David Beguin Co-Authored-By: Thibault Delavallée --- addons/website_event_track_online/__init__.py | 2 + .../__manifest__.py | 10 ++ .../controllers/__init__.py | 4 + .../controllers/event_track.py | 68 ++++++++++ .../data/event_track_demo.xml | 15 ++ .../data/event_track_visitor_demo.xml | 15 ++ .../models/__init__.py | 6 + .../models/event_track.py | 128 ++++++++++++++++++ .../models/event_track_visitor.py | 32 +++++ .../models/website_visitor.py | 75 ++++++++++ .../security/ir.model.access.csv | 3 + .../static/src/js/event_track_reminder.js | 86 ++++++++++++ .../src/scss/event_track_templates.scss | 44 ++++++ .../views/assets.xml | 13 ++ .../views/event_menus.xml | 11 ++ .../views/event_track_templates.xml | 31 +++++ .../views/event_track_templates_reminder.xml | 24 ++++ .../views/event_track_views.xml | 69 ++++++++++ .../views/event_track_visitor_views.xml | 70 ++++++++++ .../views/website_visitor_views.xml | 51 +++++++ 20 files changed, 757 insertions(+) create mode 100644 addons/website_event_track_online/controllers/__init__.py create mode 100644 addons/website_event_track_online/controllers/event_track.py create mode 100644 addons/website_event_track_online/data/event_track_demo.xml create mode 100644 addons/website_event_track_online/data/event_track_visitor_demo.xml create mode 100644 addons/website_event_track_online/models/__init__.py create mode 100644 addons/website_event_track_online/models/event_track.py create mode 100644 addons/website_event_track_online/models/event_track_visitor.py create mode 100644 addons/website_event_track_online/models/website_visitor.py create mode 100644 addons/website_event_track_online/security/ir.model.access.csv create mode 100644 addons/website_event_track_online/static/src/js/event_track_reminder.js create mode 100644 addons/website_event_track_online/static/src/scss/event_track_templates.scss create mode 100644 addons/website_event_track_online/views/assets.xml create mode 100644 addons/website_event_track_online/views/event_menus.xml create mode 100644 addons/website_event_track_online/views/event_track_templates.xml create mode 100644 addons/website_event_track_online/views/event_track_templates_reminder.xml create mode 100644 addons/website_event_track_online/views/event_track_views.xml create mode 100644 addons/website_event_track_online/views/event_track_visitor_views.xml create mode 100644 addons/website_event_track_online/views/website_visitor_views.xml diff --git a/addons/website_event_track_online/__init__.py b/addons/website_event_track_online/__init__.py index 66a1383e8f3..5a31f331a2a 100644 --- a/addons/website_event_track_online/__init__.py +++ b/addons/website_event_track_online/__init__.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import controllers +from . import models from . import tests diff --git a/addons/website_event_track_online/__manifest__.py b/addons/website_event_track_online/__manifest__.py index 95db4436abf..c85e7abeea5 100644 --- a/addons/website_event_track_online/__manifest__.py +++ b/addons/website_event_track_online/__manifest__.py @@ -16,8 +16,18 @@ 'website_event_track', ], 'data': [ + 'security/ir.model.access.csv', + 'views/assets.xml', + 'views/event_track_templates_reminder.xml', + 'views/event_track_templates.xml', + 'views/event_track_views.xml', + 'views/event_track_visitor_views.xml', + 'views/website_visitor_views.xml', + 'views/event_menus.xml', ], 'demo': [ + 'data/event_track_demo.xml', + 'data/event_track_visitor_demo.xml', ], 'application': False, 'installable': True, diff --git a/addons/website_event_track_online/controllers/__init__.py b/addons/website_event_track_online/controllers/__init__.py new file mode 100644 index 00000000000..e3798014924 --- /dev/null +++ b/addons/website_event_track_online/controllers/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import event_track diff --git a/addons/website_event_track_online/controllers/event_track.py b/addons/website_event_track_online/controllers/event_track.py new file mode 100644 index 00000000000..5217765f3fc --- /dev/null +++ b/addons/website_event_track_online/controllers/event_track.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from werkzeug.exceptions import Forbidden, NotFound + +from odoo import exceptions, http +from odoo.http import request + + +class WebsiteEventTrackController(http.Controller): + + def _fetch_track(self, track_id, allow_is_accepted=False): + track = request.env['event.track'].browse(track_id).exists() + if not track: + raise NotFound() + try: + track.check_access_rights('read') + track.check_access_rule('read') + except exceptions.AccessError: + track_sudo = track.sudo() + if allow_is_accepted and track_sudo.is_accepted: + track = track_sudo + else: + raise Forbidden() + + event = track.event_id + # JSON RPC have no website in requests + if hasattr(request, 'website_id') and not event.can_access_from_current_website(): + raise NotFound() + try: + event.check_access_rights('read') + event.check_access_rule('read') + except exceptions.AccessError: + raise Forbidden() + + return track + + @http.route("/event/track/toggle_reminder", type="json", auth="public", website=True) + def track_reminder_toggle(self, track_id, set_reminder_on): + """ Set a reminder a track for current visitor. Track visitor is created or updated + if it already exists. Exception made if un-wishlisting and no track_visitor + record found (should not happen unless manually done). + + :param boolean set_reminder_on: + If True, set as a wishlist, otherwise un-wishlist track; + If the track is a Key Track (wishlisted_by_default): + if set_reminder_on = False, blacklist the track_partner + otherwise, un-blacklist the track_partner + """ + track = self._fetch_track(track_id, allow_is_accepted=True) + force_create = set_reminder_on or track.wishlisted_by_default + event_track_partner = track._get_event_track_visitors(force_create=force_create) + visitor_sudo = event_track_partner.visitor_id + + if not track.wishlisted_by_default: + if not event_track_partner or event_track_partner.is_wishlisted == set_reminder_on: # ignore if new state = old state + return {'error': 'ignored'} + event_track_partner.is_wishlisted = set_reminder_on + else: + if not event_track_partner or event_track_partner.is_blacklisted != set_reminder_on: # ignore if new state = old state + return {'error': 'ignored'} + event_track_partner.is_blacklisted = not set_reminder_on + + result = {'reminderOn': set_reminder_on} + if request.httprequest.cookies.get('visitor_uuid', '') != visitor_sudo.access_token: + result['visitor_uuid'] = visitor_sudo.access_token + + return result diff --git a/addons/website_event_track_online/data/event_track_demo.xml b/addons/website_event_track_online/data/event_track_demo.xml new file mode 100644 index 00000000000..79bcd16929d --- /dev/null +++ b/addons/website_event_track_online/data/event_track_demo.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/addons/website_event_track_online/data/event_track_visitor_demo.xml b/addons/website_event_track_online/data/event_track_visitor_demo.xml new file mode 100644 index 00000000000..3217d3ce709 --- /dev/null +++ b/addons/website_event_track_online/data/event_track_visitor_demo.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/addons/website_event_track_online/models/__init__.py b/addons/website_event_track_online/models/__init__.py new file mode 100644 index 00000000000..645b184349c --- /dev/null +++ b/addons/website_event_track_online/models/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import event_track_visitor +from . import event_track +from . import website_visitor diff --git a/addons/website_event_track_online/models/event_track.py b/addons/website_event_track_online/models/event_track.py new file mode 100644 index 00000000000..6413c411506 --- /dev/null +++ b/addons/website_event_track_online/models/event_track.py @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models +from odoo.osv import expression + + +class Track(models.Model): + _name = "event.track" + _inherit = ['event.track'] + + # wishlist / visitors management + event_track_visitor_ids = fields.One2many( + 'event.track.visitor', 'track_id', string="Track Visitors", + groups="event.group_event_user") + is_reminder_on = fields.Boolean('Is Reminder On', compute='_compute_is_reminder_on') + wishlist_visitor_ids = fields.Many2many( + 'website.visitor', string="Visitor Wishlist", + compute="_compute_wishlist_visitor_ids", compute_sudo=True, + search="_search_wishlist_visitor_ids", + groups="event.group_event_user") + wishlist_visitor_count = fields.Integer( + string="# Wishlisted", + compute="_compute_wishlist_visitor_ids", compute_sudo=True, + groups="event.group_event_user") + wishlisted_by_default = fields.Boolean( + string='Always Wishlisted', + help="""If set, the talk will be starred for each attendee registered to the event. The attendee won't be able to un-star this talk.""") + + # WISHLIST / VISITOR MANAGEMENT + + @api.depends('wishlisted_by_default', 'event_track_visitor_ids.visitor_id', + 'event_track_visitor_ids.partner_id', 'event_track_visitor_ids.is_wishlisted', + 'event_track_visitor_ids.is_blacklisted') + @api.depends_context('uid') + def _compute_is_reminder_on(self): + current_visitor = self.env['website.visitor']._get_visitor_from_request(force_create=False) + if self.env.user._is_public() and not current_visitor: + for track in self: + track.is_reminder_on = track.wishlisted_by_default + else: + if self.env.user._is_public(): + domain = [('visitor_id', '=', current_visitor.id)] + elif 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)] + + event_track_visitors = self.env['event.track.visitor'].sudo().search_read( + expression.AND([ + domain, + [('track_id', 'in', self.ids)] + ]), fields=['track_id', 'is_wishlisted', 'is_blacklisted'] + ) + + wishlist_map = { + track_visitor['track_id'][0]: { + 'is_wishlisted': track_visitor['is_wishlisted'], + 'is_blacklisted': track_visitor['is_blacklisted'] + } for track_visitor in event_track_visitors + } + for track in self: + if wishlist_map.get(track.id): + track.is_reminder_on = wishlist_map.get(track.id)['is_wishlisted'] or (track.wishlisted_by_default and not wishlist_map[track.id]['is_blacklisted']) + else: + track.is_reminder_on = track.wishlisted_by_default + + @api.depends('event_track_visitor_ids.visitor_id', 'event_track_visitor_ids.is_wishlisted') + def _compute_wishlist_visitor_ids(self): + results = self.env['event.track.visitor'].read_group( + [('track_id', 'in', self.ids), ('is_wishlisted', '=', True)], + ['track_id', 'visitor_id:array_agg'], + ['track_id'] + ) + visitor_ids_map = {result['track_id'][0]: result['visitor_id'] for result in results} + for track in self: + track.wishlist_visitor_ids = visitor_ids_map.get(track.id, []) + track.wishlist_visitor_count = len(visitor_ids_map.get(track.id, [])) + + def _search_wishlist_visitor_ids(self, operator, operand): + if operator == "not in": + raise NotImplementedError("Unsupported 'Not In' operation on track wishlist visitors") + + track_visitors = self.env['event.track.visitor'].sudo().search([ + ('visitor_id', operator, operand), + ('is_wishlisted', '=', True) + ]) + return [('id', 'in', track_visitors.track_id.ids)] + + # ------------------------------------------------------------ + # TOOLS + # ------------------------------------------------------------ + + def _get_event_track_visitors(self, force_create=False): + self.ensure_one() + + force_visitor_create = self.env.user._is_public() + visitor_sudo = self.env['website.visitor']._get_visitor_from_request(force_create=force_visitor_create) + if visitor_sudo: + visitor_sudo._update_visitor_last_visit() + + if self.env.user._is_public(): + domain = [('visitor_id', '=', visitor_sudo.id)] + elif visitor_sudo: + domain = [ + '|', + ('partner_id', '=', self.env.user.partner_id.id), + ('visitor_id', '=', visitor_sudo.id) + ] + else: + domain = [('partner_id', '=', self.env.user.partner_id.id)] + + track_visitors = self.env['event.track.visitor'].sudo().search( + expression.AND([domain, [('track_id', 'in', self.ids)]]) + ) + missing = self - track_visitors.track_id + if missing and force_create: + track_visitors += self.env['event.track.visitor'].sudo().create([{ + 'visitor_id': visitor_sudo.id, + 'partner_id': self.env.user.partner_id.id if not self.env.user._is_public() else False, + 'track_id': track.id, + } for track in missing]) + + return track_visitors diff --git a/addons/website_event_track_online/models/event_track_visitor.py b/addons/website_event_track_online/models/event_track_visitor.py new file mode 100644 index 00000000000..b84d7c6a4d2 --- /dev/null +++ b/addons/website_event_track_online/models/event_track_visitor.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + + +class TrackVisitor(models.Model): + """ Table linking track and visitors. """ + _name = 'event.track.visitor' + _description = 'Track / Visitor Link' + _table = 'event_track_visitor' + _rec_name = 'track_id' + _order = 'track_id' + + partner_id = fields.Many2one( + 'res.partner', string='Partner', compute='_compute_partner_id', + index=True, ondelete='set null', readonly=False, store=True) + visitor_id = fields.Many2one( + 'website.visitor', string='Visitor', index=True, ondelete='cascade') + track_id = fields.Many2one( + 'event.track', string='Track', + index=True, required=True, ondelete='cascade') + is_wishlisted = fields.Boolean(string="Is Wishlisted") + is_blacklisted = fields.Boolean(string="Is reminder off", help="As key track cannot be un-wishlisted, this field store the partner choice to remove the reminder for key tracks.") + + @api.depends('visitor_id') + def _compute_partner_id(self): + for track_visitor in self: + if track_visitor.visitor_id.partner_id and not track_visitor.partner_id: + track_visitor.partner_id = track_visitor.visitor_id.partner_id + elif not track_visitor.partner_id: + track_visitor.partner_id = False diff --git a/addons/website_event_track_online/models/website_visitor.py b/addons/website_event_track_online/models/website_visitor.py new file mode 100644 index 00000000000..18072c86d11 --- /dev/null +++ b/addons/website_event_track_online/models/website_visitor.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + + +class WebsiteVisitor(models.Model): + _name = 'website.visitor' + _inherit = ['website.visitor'] + + event_track_visitor_ids = fields.One2many( + 'event.track.visitor', 'visitor_id', string="Track Visitors", + groups='event.group_event_user') + event_track_wishlisted_ids = fields.Many2many( + 'event.track', string="Wishlisted Tracks", + compute="_compute_event_track_wishlisted_ids", compute_sudo=True, + search="_search_event_track_wishlisted_ids", + groups="event.group_event_user") + event_track_wishlisted_count = fields.Integer( + string="# Wishlisted", + compute="_compute_event_track_wishlisted_ids", compute_sudo=True, + groups='event.group_event_user') + + @api.depends('parent_id', 'event_track_visitor_ids.track_id', 'event_track_visitor_ids.is_wishlisted') + def _compute_event_track_wishlisted_ids(self): + # include parent's track visitors in a visitor o2m field. We don't add + # child one as child should not have track visitors (moved to the parent) + all_visitors = self + self.parent_id + results = self.env['event.track.visitor'].read_group( + [('visitor_id', 'in', all_visitors.ids), ('is_wishlisted', '=', True)], + ['visitor_id', 'track_id:array_agg'], + ['visitor_id'] + ) + track_ids_map = {result['visitor_id'][0]: result['track_id'] for result in results} + for visitor in self: + visitor_track_ids = track_ids_map.get(visitor.id, []) + parent_track_ids = track_ids_map.get(visitor.parent_id.id, []) + visitor.event_track_wishlisted_ids = visitor_track_ids + [track_id for track_id in parent_track_ids if track_id not in visitor_track_ids] + visitor.event_track_wishlisted_count = len(visitor.event_track_wishlisted_ids) + + def _search_event_track_wishlisted_ids(self, operator, operand): + """ Search visitors with terms on wishlisted tracks. E.g. [('event_track_wishlisted_ids', + 'in', [1, 2])] should return visitors having wishlisted tracks 1, 2 as + well as their children for notification purpose. """ + if operator == "not in": + raise NotImplementedError("Unsupported 'Not In' operation on track wishlist visitors") + + track_visitors = self.env['event.track.visitor'].sudo().search([ + ('track_id', operator, operand), + ('is_wishlisted', '=', True) + ]) + if track_visitors: + visitors = track_visitors.visitor_id + # search children, even archived one, to contact them + children = self.env['website.visitor'].with_context( + active_test=False + ).sudo().search([('parent_id', 'in', visitors.ids)]) + visitor_ids = (visitors + children).ids + else: + visitor_ids = [] + + return [('id', 'in', visitor_ids)] + + def _link_to_partner(self, partner, update_values=None): + """ Propagate partner update to track_visitor records """ + if partner: + track_visitor_wo_partner = self.event_track_visitor_ids.filtered(lambda track_visitor: not track_visitor.partner_id) + if track_visitor_wo_partner: + track_visitor_wo_partner.partner_id = partner + super(WebsiteVisitor, self)._link_to_partner(partner, update_values=update_values) + + def _link_to_visitor(self, target, keep_unique=True): + """ Override linking process to link wishlist to the final visitor. """ + self.event_track_visitor_ids.visitor_id = target.id + return super(WebsiteVisitor, self)._link_to_visitor(target, keep_unique=keep_unique) diff --git a/addons/website_event_track_online/security/ir.model.access.csv b/addons/website_event_track_online/security/ir.model.access.csv new file mode 100644 index 00000000000..d756041a499 --- /dev/null +++ b/addons/website_event_track_online/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +event_track_visitor_access_all,event.track.visitor.access.all,model_event_track_visitor,,0,0,0,0 +event_track_visitor_access_manager,event.track.visitor.access.manager,model_event_track_visitor,event.group_event_manager,1,1,1,1 diff --git a/addons/website_event_track_online/static/src/js/event_track_reminder.js b/addons/website_event_track_online/static/src/js/event_track_reminder.js new file mode 100644 index 00000000000..cd0f59a44ef --- /dev/null +++ b/addons/website_event_track_online/static/src/js/event_track_reminder.js @@ -0,0 +1,86 @@ +odoo.define('website_event_track.website_event_track_reminder', function (require) { +'use strict'; + +var core = require('web.core'); +var _t = core._t; +var utils = require('web.utils'); +var publicWidget = require('web.public.widget'); + +publicWidget.registry.websiteEventTrackReminder = publicWidget.Widget.extend({ + selector: '.o_wetrack_js_reminder', + events: { + 'click': '_onReminderToggleClick', + }, + + /** + * @override + */ + init: function () { + this._super.apply(this, arguments); + this._onReminderToggleClick = _.debounce(this._onReminderToggleClick, 500, true); + }, + + //-------------------------------------------------------------------------- + // Handlers + //------------------------------------------------------------------------- + + /** + * @private + * @param {Event} ev + */ + _onReminderToggleClick: function (ev) { + ev.stopPropagation(); + ev.preventDefault(); + var self = this; + var $trackLink = $(ev.currentTarget).find('i'); + + if (this.reminderOn === undefined) { + this.reminderOn = $trackLink.data('reminderOn'); + } + + this._rpc({ + route: '/event/track/toggle_reminder', + params: { + track_id: $trackLink.data('trackId'), + set_reminder_on: !this.reminderOn + }, + }).then(function (result) { + if (result.error && result.error === 'ignored') { + self.displayNotification({ + type: 'info', + title: _t('Error'), + message: _.str.sprintf(_t('Talk already in your Favorites')), + }); + } else { + self.reminderOn = result.reminderOn; + var reminderText = self.reminderOn ? _t('Reminder On') : _t('Set Reminder'); + self.$('.o_wetrack_js_reminder_text').text(reminderText); + self._updateDisplay(); + var message = self.reminderOn ? _t('Talk added to your Favorites') : _t('Talk removed from your Favorites'); + self.displayNotification({ + type: 'info', + title: message + }); + } + if (result.visitor_uuid) { + utils.set_cookie('visitor_uuid', result.visitor_uuid); + } + }); + }, + + _updateDisplay: function () { + var $trackLink = this.$el.find('i'); + if (this.reminderOn) { + $trackLink.addClass('fa-bell').removeClass('fa-bell-o'); + $trackLink.attr('title', _t('Reminder On')); + } else { + $trackLink.addClass('fa-bell-o').removeClass('fa-bell'); + $trackLink.attr('title', _t('Set Reminder')); + } + }, + +}); + +return publicWidget.registry.websiteEventTrackReminder; + +}); diff --git a/addons/website_event_track_online/static/src/scss/event_track_templates.scss b/addons/website_event_track_online/static/src/scss/event_track_templates.scss new file mode 100644 index 00000000000..133862c3997 --- /dev/null +++ b/addons/website_event_track_online/static/src/scss/event_track_templates.scss @@ -0,0 +1,44 @@ +/* + * EVENT TOOL: REMINDER WIDGET + */ +.o_wevent_event .o_wetrack_js_reminder { + width: fit-content; + height: fit-content; + cursor: pointer; + background: grey; + + i { + &.fa-bell { + color: gold; + } + &.fa-bell-o { + color: white + } + } + + // Icon only + &.o_wetrack_reminder_light { + background: transparent; + padding: 0; + i { + &.inactive_color_dark { + color: grey; + } + } + &:not(.o_wetrack_reminder_small) { + i { + font-size: 1.5em; + } + } + } + + // Text included + &:not(.o_wetrack_reminder_light) { + &.o_wetrack_reminder_small { + padding: 0.25rem 0.50rem; + span { + min-width: 70px; + } + } + } +} diff --git a/addons/website_event_track_online/views/assets.xml b/addons/website_event_track_online/views/assets.xml new file mode 100644 index 00000000000..ca095992bb0 --- /dev/null +++ b/addons/website_event_track_online/views/assets.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/addons/website_event_track_online/views/event_menus.xml b/addons/website_event_track_online/views/event_menus.xml new file mode 100644 index 00000000000..a4685ab02d6 --- /dev/null +++ b/addons/website_event_track_online/views/event_menus.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/addons/website_event_track_online/views/event_track_templates.xml b/addons/website_event_track_online/views/event_track_templates.xml new file mode 100644 index 00000000000..6ca0cfbc5de --- /dev/null +++ b/addons/website_event_track_online/views/event_track_templates.xml @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/addons/website_event_track_online/views/event_track_templates_reminder.xml b/addons/website_event_track_online/views/event_track_templates_reminder.xml new file mode 100644 index 00000000000..2771cda1307 --- /dev/null +++ b/addons/website_event_track_online/views/event_track_templates_reminder.xml @@ -0,0 +1,24 @@ + + + + + + + diff --git a/addons/website_event_track_online/views/event_track_views.xml b/addons/website_event_track_online/views/event_track_views.xml new file mode 100644 index 00000000000..6499c869e39 --- /dev/null +++ b/addons/website_event_track_online/views/event_track_views.xml @@ -0,0 +1,69 @@ + + + + Visitors Wishlist + website.visitor + kanban,tree,form,graph + [('event_track_wishlisted_ids', 'in', [active_id])] + +

+ Wait for visitors to wishlist your tracks +

+
+
+ + + event.track.view.search.inherit.event.track.online + event.track + + + + + + + + + + event.track.view.tree.inherit.event.track.online + event.track + + + + + + + + + + + event.track.view.form.inherit.event.track.online + event.track + + + + + + + + + + + + + Wishlisted Tracks + event.track + kanban,tree,form + [('wishlist_visitor_ids', 'in', [active_id])] + +

+ No track wishlisted by this visitor +

+
+
+ +
diff --git a/addons/website_event_track_online/views/event_track_visitor_views.xml b/addons/website_event_track_online/views/event_track_visitor_views.xml new file mode 100644 index 00000000000..2a90e7f5d46 --- /dev/null +++ b/addons/website_event_track_online/views/event_track_visitor_views.xml @@ -0,0 +1,70 @@ + + + + + event.track.visitor.view.search + event.track.visitor + + + + + + + + + + + + + + + + + event.track.visitor.view.form + event.track.visitor + +
+ + + + + + + + + + + + +
+
+
+ + + event.track.visitor.view.list + event.track.visitor + + + + + + + + + + + + Track Visitors + event.track.visitor + tree,form + +

+ Add a new track visitor +

+ Track Visitors store statistics on track attendance, including + wishlist management. +

+
+
+ +
diff --git a/addons/website_event_track_online/views/website_visitor_views.xml b/addons/website_event_track_online/views/website_visitor_views.xml new file mode 100644 index 00000000000..c5ee8456984 --- /dev/null +++ b/addons/website_event_track_online/views/website_visitor_views.xml @@ -0,0 +1,51 @@ + + + + + website.visitor.view.tree.inherit.event.track + website.visitor + + + + + + + + + + website.visitor.view.form.inherit.event.track + website.visitor + + + + + + + + + + website.visitor.view.kanban.inherit.event.track + website.visitor + + + + + + +
Wishlisted Tracks
+
+ +
+ +
Wishlisted Tracks
+
+
+
+
+ +