diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3efb4d9157dc36d84e372eec5fc21e7f4a417a58..44c49f1b36f02734db32be0926be954ee5c0e3cf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -61,6 +61,7 @@ repos: hooks: - id: prettier name: prettier (with plugin-xml) + exclude: ^templates/ additional_dependencies: - "prettier@2.7.1" - "@prettier/plugin-xml@2.2.0" diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..2bc20bc9b813b1c6802c232a95e763239c812ff4 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# CG SCOP - Website Event +## Description +Customisation du module *website_event* pour la CG Scop : + +* Ajoute les menus *Programme* et Hébergement* par défaut +* Ajout du nom et prénom sur une réservation + +## Credits + +The development of this module has been financially supported by: + - CG Scop + +## Contributors + +* Benjamin Rivier <benjamin@le-filament.com> + + +## Maintainer + + +[](https://le-filament.com) +This module is maintained by Le Filament + +## Licenses + +This repository is licensed under [AGPL-3.0](LICENSE). + diff --git a/README.rst b/README.rst deleted file mode 100644 index d8faad1edddfea217ea5352e69d59c1c2b0104e7..0000000000000000000000000000000000000000 --- a/README.rst +++ /dev/null @@ -1,41 +0,0 @@ -.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg - :target: http://www.gnu.org/licenses/agpl.html - :alt: License: AGPL-3 - - -======================= -CG SCOP - Website Event -======================= - -Description -=========== - -Customisation du module *website_event* pour la CG Scop. -- Ajout des réservations non confirmées sur la prise en compte des places max sur un évènement -- Ajout du nom et prénom sur une réservation -- Ajout des sessions sur le site web -- Ajout des créneaux sur les sessions (gestion ateliers sur premier jour) -- Ajout des tags sur les sessions -- Ajout de la compagnie sur les tags - - -Credits -======= - -The development of this module has been financially supported by: - - CG Scop - -Contributors ------------- - -* Benjamin Rivier <benjamin@le-filament.com> - - -Maintainer ----------- - -.. image:: https://le-filament.com/img/logo-lefilament.png - :alt: Le Filament - :target: https://le-filament.com - -This module is maintained by Le Filament diff --git a/__init__.py b/__init__.py index 72d3ea60a8cf7cd1d26a4066c05e6817315bce8b..0650744f6bc69b9f0b865e8c7174c813a5f5995e 100644 --- a/__init__.py +++ b/__init__.py @@ -1 +1 @@ -from . import controllers, models +from . import models diff --git a/__manifest__.py b/__manifest__.py index 3d81a3f5eb0633435abdfc2328c36234763aad4a..b7f4e978ab0ba7dcdc20290c5487daa5a9874232 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -7,33 +7,21 @@ "development_status": "Beta", "license": "AGPL-3", "depends": [ - "event_session", "partner_firstname", "website_event", - "website_event_questions", ], "data": [ # security - "security/session_security.xml", - "security/ir.model.access.csv", + # templates + "templates/hosting.xml", + "templates/program.xml", + "templates/page_registration.xml", # views - "views/event_session_views.xml", - "views/event_session_page_templates.xml", - "views/event_session_agenda_templates.xml", - "views/event_session_template_list.xml", - "views/event_template.xml", - "views/event_template_page_registration.xml", "views/event_views.xml", - "views/event_tag_views.xml", - "data/mail_data.xml", + "views/event_registration_views.xml", # report ], - "assets": { - "web.assets_frontend": [ - "cgscop_website_event/static/src/scss/cgscop_website_event.scss", - "cgscop_website_event/static/src/js/website_event_session.js", - ], - }, + "assets": {}, "installable": True, "auto_install": False, } diff --git a/controllers/__init__.py b/controllers/__init__.py deleted file mode 100644 index 6b1029b1764bcd1020285c8e4ce7535f53de9daf..0000000000000000000000000000000000000000 --- a/controllers/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright 2023 Le Filament (<http://www.le-filament.com>) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -from . import main diff --git a/controllers/main.py b/controllers/main.py deleted file mode 100644 index 185154e1e6fa8d32c8cfbe183b624b578a5c88cc..0000000000000000000000000000000000000000 --- a/controllers/main.py +++ /dev/null @@ -1,636 +0,0 @@ -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -import copy -import re -from ast import literal_eval -from datetime import timedelta - -import babel -import babel.dates -import pytz -import werkzeug -from pytz import timezone, utc -from werkzeug.exceptions import Forbidden, NotFound - -from odoo import exceptions, fields, http -from odoo.http import request -from odoo.osv import expression -from odoo.tools import is_html_empty -from odoo.tools.misc import babel_locale_parse - -from odoo.addons.website_event.controllers.main import WebsiteEventController -from odoo.addons.website_event_questions.controllers.main import WebsiteEvent - - -class WebsiteEventController(WebsiteEventController): - def _get_event_sessions_agenda_domain(self, event): - agenda_domain = [ - "&", - ("event_id", "=", event.id), - ("is_published", "=", True), - ] - return agenda_domain - - def _get_event_sessions_domain(self, event): - search_domain_base = self._get_event_sessions_agenda_domain(event) - if not request.env.user.has_group("event.group_event_registration_desk"): - search_domain_base = expression.AND( - [search_domain_base, [("is_published", "=", True)]] - ) - return search_domain_base - - @http.route( - ["""/event/<model("event.event"):event>/page/<path:page>"""], - type="http", - auth="public", - website=True, - sitemap=False, - ) - def event_page(self, event, page, **post): - values = { - "event": event, - } - - if "." not in page: - page = "website_event.%s" % page - - try: - # Every event page view should have its own SEO. - values["seo_object"] = request.website.get_template(page) - values["main_object"] = event - except ValueError: - # page not found - values["path"] = re.sub(r"^website_event\.", "", page) - values[ - "from_template" - ] = "website_event.default_page" # .strip('website_event.') - page = ( - request.env.user.has_group("website.group_website_designer") - and "website.page_404" - or "http_routing.404" - ) - - return request.render(page, values) - - # ------------------------------------------------------------ - # session LIST VIEW - # ------------------------------------------------------------ - @http.route( - [ - """/event/<model("event.event"):event>/session""", - """/event/<model("event.event"):event>/session/tag/<model("event.tag"):tag>""", - ], - type="http", - auth="public", - website=True, - sitemap=False, - ) - def event_sessions(self, event, tag=None, **searches): - """Main route - - :param event: event whose sessions are about to be displayed; - :param tag: deprecated: search for a specific tag - :param searches: frontend search dict, containing - - * 'search': search string; - * 'tags': list of tag IDs for filtering; - """ - return request.render( - "cgscop_website_event.sessions_session", - self._event_sessions_get_values(event, tag=tag, **searches), - ) - - def _event_sessions_get_values(self, event, tag=None, **searches): - # init and process search terms - searches.setdefault("search", "") - searches.setdefault("tags", "") - search_domain = self._get_event_sessions_agenda_domain(event) - - # search on content - if searches.get("search"): - search_domain = expression.AND( - [search_domain, [("name", "ilike", searches["search"])]] - ) - - # search on tags - search_tags = self._get_search_tags(searches["tags"]) - if not search_tags and tag: - search_tags = tag - if search_tags: - grouped_tags = dict() - for search_tag in search_tags: - grouped_tags.setdefault(search_tag.category_id, list()).append( - search_tag - ) - search_domain_items = [ - [("tag_ids", "in", [tag.id for tag in grouped_tags[group]])] - for group in grouped_tags - ] - search_domain = expression.AND([search_domain, *search_domain_items]) - - # fetch data to display with TZ set for both event and sessions - now_tz = utc.localize( - fields.Datetime.now().replace(microsecond=0), is_dst=False - ).astimezone(timezone(event.date_tz)) - today_tz = now_tz.date() - event = event.with_context(tz=event.date_tz or "UTC") - sessions_sudo = ( - event.env["event.session"] - .sudo() - .search(search_domain, order="is_published desc, date_begin asc") - ) - tag_categories = request.env["event.tag.category"].search( - [("is_published", "=", True)] - ) - - # organize categories for display: announced, live, soon and day-based - sessions_announced = sessions_sudo.filtered( - lambda session: not session.date_begin - ) - sessions_wdate = sessions_sudo - sessions_announced - date_begin_tz_all = list( - { - dt.date() - for dt in self._get_dt_in_event_tz( - sessions_wdate.mapped("date_begin"), event - ) - } - ) - date_begin_tz_all.sort() - - sessions_by_day = [] - for display_date in date_begin_tz_all: - matching_sessions = sessions_wdate.filtered( - lambda session: self._get_dt_in_event_tz([session.date_begin], event)[ - 0 - ].date() - == display_date - ) - sessions_by_day.append( - { - "date_begin": display_date, - "name": display_date, - "sessions": matching_sessions, - } - ) - - for sessions_group in sessions_by_day: - sessions_group["default_collapsed"] = ( - today_tz != sessions_group["date_begin"] - ) - - # return rendering values - return { - # event information - "event": event, - "main_object": event, - # sessions display information - "sessions": sessions_sudo, - "sessions_by_day": sessions_by_day, - "today_tz": today_tz, - # search information - "searches": searches, - "search_key": searches["search"], - "search_tags": search_tags, - "tag_categories": tag_categories, - # environment - "is_html_empty": is_html_empty, - "hostname": request.httprequest.host.split(":")[0], - "is_event_user": request.env.user.has_group("event.group_event_user"), - } - - # ------------------------------------------------------------ - # AGENDA VIEW - # ------------------------------------------------------------ - - @http.route( - ["""/event/<model("event.event"):event>/agenda-sessions"""], - type="http", - auth="public", - website=True, - sitemap=False, - ) - def event_agenda_session(self, event, tag=None, **post): - post.setdefault("tags", "") - event = event.with_context(tz=event.date_tz or "UTC") - tag_categories = request.env["event.tag.category"].search( - [("is_published", "=", True)] - ) - search_domain_items = [] - # search on tags - search_tags = self._get_search_tags(post["tags"]) - if not search_tags and tag: - search_tags = tag - if search_tags: - grouped_tags = dict() - for search_tag in search_tags: - grouped_tags.setdefault(search_tag.category_id, list()).append( - search_tag - ) - search_domain_items = [ - [("tag_ids", "in", [tag.id for tag in grouped_tags[group]])] - for group in grouped_tags - ] - - vals = { - "search_tags": search_tags, - "tag_categories": tag_categories, - "event": event, - "main_object": event, - "tag": tag, - "is_event_user": request.env.user.has_group("event.group_event_user"), - } - - vals.update(self._prepare_calendar_values(event, search_domain_items)) - - return request.render("cgscop_website_event.agenda_online", vals) - - def _prepare_calendar_values(self, event, search_domain_items=False): - """This methods slit the day (max end time - min start time) into - 15 minutes time slots. For each time slot, we assign the sessions that - start at this specific time slot, and we add the number of time slot - that the session covers (session duration / 15 min). The calendar will be - divided into rows of 15 min, and the talks will cover the corresponding - number of rows (15 min slots). - Same function as tracks""" - event = event.with_context(tz=event.date_tz or "UTC") - local_tz = pytz.timezone(event.date_tz or "UTC") - lang_code = request.env.context.get("lang") - - base_session_domain = expression.AND( - [ - self._get_event_sessions_agenda_domain(event), - [("date_begin", "!=", False)], - ] - ) - if search_domain_items: - base_session_domain = expression.AND( - [base_session_domain, *search_domain_items] - ) - - sessions_sudo = request.env["event.session"].sudo().search(base_session_domain) - - # First split day by day (based on start time) - time_slots_by_sessions = { - session: self._split_session_by_days(session, local_tz) - for session in sessions_sudo - } - - # extract all the sessions time slots - session_time_slots = set().union( - *( - time_slot.keys() - for time_slot in [ - time_slots for time_slots in time_slots_by_sessions.values() - ] - ) - ) - - # extract unique days - days = list({time_slot.date() for time_slot in session_time_slots}) - days.sort() - - # Create the dict that contains the sessions at the correct time_slots - sessions_by_days = dict.fromkeys(days, 0) - time_slots_by_day = {day: dict(start=set(), end=set()) for day in days} - sessions_by_rounded_times = {time_slot: {} for time_slot in session_time_slots} - for session, time_slots in time_slots_by_sessions.items(): - start_date = ( - fields.Datetime.from_string(session.date_begin) - .replace(tzinfo=pytz.utc) - .astimezone(local_tz) - ) - end_date = start_date + timedelta(hours=(session.duration or 0.25)) - - for time_slot, duration in time_slots.items(): - sessions_by_rounded_times[time_slot][session] = { - "rowspan": duration, - "start_date": self._get_locale_time(start_date, lang_code), - "end_date": self._get_locale_time(end_date, lang_code), - "occupied_cells": self._get_occupied_cells( - session, duration, local_tz - ), - } - - # get all the time slots by day to determine the max duration of a day. - day = time_slot.date() - time_slots_by_day[day]["start"].add(time_slot) - time_slots_by_day[day]["end"].add( - time_slot + timedelta(minutes=15 * duration) - ) - sessions_by_days[day] += 1 - - # split days into 15 minutes time slots - global_time_slots_by_day = {day: {} for day in days} - for day, time_slots in time_slots_by_day.items(): - start_time_slot = min(time_slots["start"]) - end_time_slot = max(time_slots["end"]) - - time_slots_count = int( - ((end_time_slot - start_time_slot).total_seconds() / 3600) * 4 - ) - current_time_slot = start_time_slot - for _i in range(0, time_slots_count + 1): - global_time_slots_by_day[day][ - current_time_slot - ] = sessions_by_rounded_times.get(current_time_slot, {}) - global_time_slots_by_day[day][current_time_slot][ - "formatted_time" - ] = self._get_locale_time(current_time_slot, lang_code) - current_time_slot = current_time_slot + timedelta(minutes=15) - - # count the number of sessions by days - sessions_by_days = dict.fromkeys(days, 0) - - for session in sessions_sudo: - for slot in session.event_session_slot_ids: - session_day = ( - fields.Datetime.from_string(slot.date) - .replace(tzinfo=pytz.utc) - .astimezone(local_tz) - .date() - ) - sessions_by_days[session_day] += 1 - - return { - "days": days, - "sessions_by_days": sessions_by_days, - "time_slots": global_time_slots_by_day, - } - - def _get_locale_time(self, dt_time, lang_code): - """Get locale time from datetime object - - :param dt_time: datetime object - :param lang_code: language code (eg. en_US) - """ - locale = babel_locale_parse(lang_code) - return babel.dates.format_time(dt_time, format="short", locale=locale) - - def time_slot_rounder(self, time, rounded_minutes): - """Rounds to nearest hour by adding a timedelta hour if minute>=rounded_minutes - E.g. : If rounded_minutes = 15 -> 09:26:00 becomes 09:30:00 - 09:17:00 becomes 09:15:00 - """ - return time.replace( - second=0, microsecond=0, minute=0, hour=time.hour - ) + timedelta(minutes=rounded_minutes * (time.minute // rounded_minutes)) - - def _split_session_by_days(self, session, local_tz): - """ - Based on the session start_date and the duration, - split the session duration into : - start_time by day : number of time slot (15 minutes) - that the session takes on that day. - E.g. : start date = 01-01-2000 10:00 PM and duration = 3 hours - return { - 01-01-2000 10:00:00 PM: 8 (2 * 4), - 01-02-2000 00:00:00 AM: 4 (1 * 4) - } - Also return a set of all the time slots - """ - time_slots_by_sessions = {} - for slot in session.event_session_slot_ids: - time_slots_by_sessions.update( - self._split_session_slot_by_days(slot, local_tz) - ) - return time_slots_by_sessions - - def _split_session_slot_by_days(self, slot, local_tz): - """ - Based on the session slot date and the duration, - split the session duration into : - start_time by day : number of time slot (15 minutes) that the session - takes on that day. - Also return a set of all the time slots - """ - start_date = ( - fields.Datetime.from_string(slot.date) - .replace(tzinfo=pytz.utc) - .astimezone(local_tz) - ) - start_datetime = self.time_slot_rounder(start_date, 15) - end_datetime = self.time_slot_rounder( - start_datetime + timedelta(hours=(slot.duration or 0.25)), 15 - ) - time_slots_count = int( - ((end_datetime - start_datetime).total_seconds() / 3600) * 4 - ) - - time_slots_by_day_start_time = {start_datetime: 0} - for i in range(0, time_slots_count): - # If the new time slot is still on the current day - next_day = (start_datetime + timedelta(days=1)).date() - if (start_datetime + timedelta(minutes=15 * i)).date() <= next_day: - time_slots_by_day_start_time[start_datetime] += 1 - else: - start_datetime = next_day.datetime() - time_slots_by_day_start_time[start_datetime] = 0 - - return time_slots_by_day_start_time - - def _get_occupied_cells(self, session, rowspan, local_tz): - occupied_cells = [] - - start_date = ( - fields.Datetime.from_string(session.date_begin) - .replace(tzinfo=pytz.utc) - .astimezone(local_tz) - ) - start_date = self.time_slot_rounder(start_date, 15) - for i in range(0, rowspan): - time_slot = start_date + timedelta(minutes=15 * i) - occupied_cells += [time_slot] - - return occupied_cells - - # ------------------------------------------------------------ - # session PAGE VIEW - # ------------------------------------------------------------ - - @http.route( - """/event/<model("event.event", "[('website_session', '=', True)]"):event> - /session/<model("event.session", "[('event_id', '=', event.id)]"):session>""", - type="http", - auth="public", - website=True, - sitemap=True, - ) - def event_session_page(self, event, session, **options): - session = self._fetch_session(session.id, allow_sudo=False) - - return request.render( - "cgscop_website_event.event_session_main", - self._event_session_page_get_values(event, session.sudo(), **options), - ) - - def _event_session_page_get_values(self, event, session, **options): - session = session.sudo() - - option_widescreen = options.get("widescreen", False) - option_widescreen = ( - bool(option_widescreen) if option_widescreen != "0" else False - ) - # search for sessions list - sessions_other = session._get_session_suggestions( - restrict_domain=self._get_event_sessions_domain(session.event_id), limit=10 - ) - - return { - # event information - "event": event, - "main_object": session, - "session": session, - # sidebar - "sessions_other": sessions_other, - # options - "option_widescreen": option_widescreen, - # environment - "is_html_empty": is_html_empty, - "hostname": request.httprequest.host.split(":")[0], - "is_event_user": request.env.user.has_group("event.group_event_user"), - "user_event_manager": request.env.user.has_group( - "event.group_event_manager" - ), - } - - @http.route( - ['/event/<model("event.event"):event>/registration/new'], - type="json", - auth="public", - methods=["POST"], - website=True, - ) - def registration_new(self, event, **post): - if event.use_sessions: - vals = self._event_sessions_get_values(event, tag=None, **post) - tickets = self._process_tickets_form(event, post) - availability_check = True - if event.seats_limited: - ordered_seats = 0 - for ticket in tickets: - ordered_seats += ticket["quantity"] - if event.seats_available < ordered_seats: - availability_check = False - if not tickets: - return False - default_first_attendee = {} - if not request.env.user._is_public(): - default_first_attendee = { - "name": request.env.user.name, - "email": request.env.user.email, - "phone": request.env.user.mobile or request.env.user.phone, - } - else: - visitor = request.env["website.visitor"]._get_visitor_from_request() - if visitor.email: - default_first_attendee = { - "name": visitor.name, - "email": visitor.email, - "phone": visitor.mobile, - } - - vals.update( - { - "tickets": tickets, - "event": event, - "availability_check": availability_check, - "default_first_attendee": default_first_attendee, - } - ) - return request.env["ir.ui.view"]._render_template( - "website_event.registration_attendee_details", vals - ) - else: - return super().registration_new(event, **post) - - # ------------------------------------------------------------ - # TOOLS - # ------------------------------------------------------------ - - def _fetch_session(self, session_id, allow_sudo=False): - session = request.env["event.session"].browse(session_id).exists() - if not session: - raise NotFound() - try: - session.check_access_rights("read") - session.check_access_rule("read") - except exceptions.AccessError as ex: - if not allow_sudo: - raise Forbidden() from ex - session = session.sudo() - - event = session.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 as ex: - raise Forbidden() from ex - - return session - - def _get_search_tags(self, tag_search): - try: - tag_ids = literal_eval(tag_search) - except Exception: - tags = request.env["event.tag"].sudo() - else: - # perform a search to filter on existing / valid tags implicitly - tags = request.env["event.tag"].sudo().search([("id", "in", tag_ids)]) - return tags - - def _get_dt_in_event_tz(self, datetimes, event): - tz_name = event.date_tz - return [ - utc.localize(dt, is_dst=False).astimezone(timezone(tz_name)) - for dt in datetimes - ] - - -class WebsiteEvent(WebsiteEvent): - @http.route() - def registration_confirm(self, event, **post): - if event.use_sessions: - registrations = self._process_attendees_form(event, post) - # Manage sessions registrations - registrations_sessions = self._process_attendees_form_sessions( - event, post, registrations - ) - attendees_sudo = self._create_attendees_from_registration_post( - event, registrations_sessions - ) - return request.redirect( - ("/event/%s/registration/success?" % event.id) - + werkzeug.urls.url_encode( - { - "registration_ids": ",".join( - [str(id) for id in attendees_sudo.ids] - ) - } - ) - ) - else: - return super().registration_confirm(event, **post) - - def _process_attendees_form_sessions(self, event, form_details, registrations): - """Process data posted from the attendee details form. - Manage sessions registrations.""" - reg = [] - for key, _value in form_details.items(): - if "session_id" in key: - text, session_id = key.split("-") - registrations_sessions = [] - registrations_sessions = copy.deepcopy(registrations) - for registration_session in registrations_sessions: - registration_session["session_id"] = int(session_id) - registration_session["registration_answer_ids"] = [] - reg += registrations_sessions - - reg_total = reg + registrations - return reg_total diff --git a/data/mail_data.xml b/data/mail_data.xml deleted file mode 100644 index 456e842048e66d62270f9bbc32c3e0583a42f1da..0000000000000000000000000000000000000000 --- a/data/mail_data.xml +++ /dev/null @@ -1,106 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<odoo> - - <!-- Template and notification section --> - <record id="email_template_confirmation_event" model="mail.template"> - <field name="name">CG Scop - 1er courriel de confirmation</field> - <field name="model_id" ref="event.model_event_registration" /> - <field name="email_from">administratif.cg@scop.coop</field> - <field - name="email_to" - >{{ (object.email and '"%s" <%s>' % (object.name, object.email) or object.partner_id.email_formatted or '') }}</field> - <field name="reply_to">administratif.cg@scop.coop</field> - <field - name="subject" - >Confirmation de votre inscription à l’évènement - Université des permanent.es 2023</field> - <field name="body_html" type="html"> - <div style="margin: 0px; padding: 0px;"> - <p style="margin: 0px; padding: 0px; font-size: 13px;"> - <p>Bonjour,</p> - <p> </p> - <p - >Nous avons le plaisir de vous informer que vous êtes bien inscrit à <t - t-out="object.event_id.name or ''" - >l’Université des permanent.es</t> du <t - t-out="object.event_id.date_begin_located or ''" - >May 4, 2021, 7:00:00 AM</t> au <t - t-out="object.event_id.date_end_located or ''" - >May 6, 2021, 5:00:00 PM</t> qui se tiendra au <t - t-if="object.event_id.address_id.name" - ><t - t-out="object.event_id.address_id.name or ''" - >Domaine de Valpré, à Ecully</t></t>.</p> - <p - >Nous reviendrons vers vous très rapidement pour vous communiquer le nom et l’adresse de votre hébergement sur place.</p> - <p> </p> - <p - >Vous recevrez également très prochainement, un courriel de confirmation de votre inscription à/aux ateliers de formation.</p> - <p> </p> - <p - >Nous vous souhaitons bonne réception de ce courriel et restons à votre disposition pour toute question. </p> - <p> </p> - <p>Bonne journée.</p> - <p> </p> - <p> - L’équipe organisatrice - </p> - </p> - </div> - </field> - <field name="lang">${object.lang}</field> - <field name="auto_delete" eval="False" /> - </record> - - <record id="email_template_confirmation_event_second" model="mail.template"> - <field name="name">CG Scop - 2ème courriel de confirmation</field> - <field name="model_id" ref="event.model_event_registration" /> - <field name="email_from">administratif.cg@scop.coop</field> - <field - name="email_to" - >{{ (object.email and '"%s" <%s>' % (object.name, object.email) or object.partner_id.email_formatted or '') }}</field> - <field name="reply_to">administratif.cg@scop.coop</field> - <field - name="subject" - >Confirmation de votre inscription aux ateliers de formation</field> - <field name="body_html" type="html"> - <div style="margin: 0px; padding: 0px;"> - <p style="margin: 0px; padding: 0px; font-size: 13px;"> - <p>Bonjour,</p> - <p> </p> - <p - >Nous avons le plaisir de vous confirmer votre inscription à l'atelier de formation :</p> - <t t-if="object.session_id" /> - <ul> - <t - t-set="date_begin" - t-value="format_datetime(object.session_id.date_begin, dt_format="dd/MM/yyyy HH:mm")" - /> - <t - t-set="date_end" - t-value="format_datetime(object.session_id.date_end, dt_format="dd/MM/yyyy HH:mm")" - /> - <li> - <b><t - t-out="object.session_id.session_name" - >Nom de la session</t></b> du <span><t - t-out="date_begin" - >date début</t> au <t - t-out="date_end" - >date fin</t></span> - </li> - </ul> - <p - >Nous vous souhaitons bonne réception de ce courriel et restons à votre disposition pour toute question. </p> - <p> </p> - <p>Bonne journée.</p> - <p> </p> - <p> - L’équipe organisatrice - </p> - </p> - </div> - </field> - <field name="lang">${object.lang}</field> - <field name="auto_delete" eval="False" /> - </record> -</odoo> diff --git a/i18n/fr.po b/i18n/fr.po deleted file mode 100644 index a941cb0e71b812f79955d90dc61870330c8d53a0..0000000000000000000000000000000000000000 --- a/i18n/fr.po +++ /dev/null @@ -1,539 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * cgscop_website_event -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 16.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-12 09:49+0000\n" -"PO-Revision-Date: 2023-06-12 09:49+0000\n" -"Last-Translator: \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: \n" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.agenda_main_session -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.event_session_content -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.registration_event_session -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.sessions_display_list -msgid "- COMPLET" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.view_event_session_form -msgid "" -"<i class=\"fa fa-long-arrow-right mx-2\" aria-label=\"Arrow icon\" " -"title=\"Arrow\"/>" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.agenda_topbar -msgid "<span id=\"search_number\" class=\"me-1\">0</span>Resultats" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.event_session_content_partner_info -msgid "<span> à </span>" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields.selection,name:cgscop_website_event.selection__event_event__type_event_cg__agenda -#: model:ir.model.fields.selection,name:cgscop_website_event.selection__event_type__type_event_cg__agenda -msgid "Agenda" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session_slot__session_id -msgid "Atelier" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__event_session_registrations_sold_out -msgid "Atelier Complet" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.event_session_aside -msgid "Ateliers" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__can_publish -msgid "Can Publish" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_tag__company_id -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_tag_category__company_id -msgid "Company" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__color -msgid "Couleur" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session_slot__create_uid -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant__create_uid -msgid "Created by" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session_slot__create_date -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant__create_date -msgid "Created on" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__event_session_slot_ids -msgid "Créneaux des ateliers" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.view_event_session_form -msgid "Date" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session_slot__date -msgid "Date de début de créneau" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session_slot__date_end -msgid "Date de fin de créneau" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__description -msgid "Description de l'atelier" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant__partner_description -msgid "Description de l'intervenant" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session_slot__display_name -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant__display_name -msgid "Display Name" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__duration -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session_slot__duration -msgid "Durée" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__duration_slot -msgid "Durée des créneaux" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.registration_event_session -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.sessions_display_list -msgid "Durée:" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__date_end -msgid "End Date" -msgstr "Date de fin" - -#. module: cgscop_website_event -#: model:ir.model,name:cgscop_website_event.model_event_event -msgid "Event" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model,name:cgscop_website_event.model_event_registration -msgid "Event Registration" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_event__session_menu_ids -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__session_menu_ids -msgid "Event Session Menus" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields.selection,name:cgscop_website_event.selection__website_event_menu__menu_type__session -msgid "Event Sessions Menus" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model,name:cgscop_website_event.model_event_tag -msgid "Event Tag" -msgstr "Étiquettes d'événement" - -#. module: cgscop_website_event -#: model:ir.model,name:cgscop_website_event.model_event_tag_category -msgid "Event Tag Category" -msgstr "Catégorie d'étiquette d'événement" - -#. module: cgscop_website_event -#: model:ir.model,name:cgscop_website_event.model_event_type -msgid "Event Template" -msgstr "Modèle d'événement" - -#. module: cgscop_website_event -#: model:ir.model,name:cgscop_website_event.model_event_event_ticket -msgid "Event Ticket" -msgstr "Ticket d'événement" - -#. module: cgscop_website_event -#: model:ir.model,name:cgscop_website_event.model_event_session -msgid "Event session" -msgstr "Séance" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.event_session_content -msgid "Evènement" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__link_auto_eval -msgid "Fiche Auto Evaluation" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.event_session_content -msgid "Fiche d'Auto Evaluation" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.agenda_topbar -msgid "Filtrer les ateliers..." -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant__partner_function -msgid "Fonction" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields.selection,name:cgscop_website_event.selection__event_event__type_event_cg__formation -#: model:ir.model.fields.selection,name:cgscop_website_event.selection__event_type__type_event_cg__formation -msgid "Formation" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session_slot__id -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant__id -msgid "ID" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.sessions_main -msgid "Il n'y a pas d'ateiliers correpondants à votre" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.agenda_online -msgid "Il n'y a pas d'ateliers correspondant à votre" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant__partner_id -msgid "Intervenant" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model,name:cgscop_website_event.model_res_partner_intervenant -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__intervenant_ids -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.event_session_content -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.view_event_session_form -msgid "Intervenants" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__is_published -msgid "Is Published" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session_slot____last_update -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant____last_update -msgid "Last Modified on" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session_slot__write_uid -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant__write_uid -msgid "Last Updated by" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session_slot__write_date -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant__write_date -msgid "Last Updated on" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.sessions_display_list -msgid "Liste des ateliers" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant__partner_email -msgid "Mail" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.registration_attendee_details_sessions -msgid "Mail *" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_website_event_menu__menu_type -msgid "Menu Type" -msgstr "Type de Menu" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.registration_attendee_details_sessions -msgid "Nom *" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__session_name -msgid "Nom de l'atelier" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant__partner_name -msgid "Nom de l'intervenant" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_registration__partner_lastname -msgid "Nom du participant" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__seats_max -msgid "Nombre maximal de participants" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__seats_min -msgid "Nombre minimum de participants" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.registration_event_session -msgid "Non Publié" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.agenda_main_session -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.sessions_display_list -msgid "Non publié" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.event_session_aside_other_session -msgid "Non publiée" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.agenda_online -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.sessions_main -msgid "Pas d'ateliers trouvés." -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.view_event_session_form -msgid "Places disponibles" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__seats_available_unconfirmed -msgid "Places disponibles en pré-inscription" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.event_session_content -msgid "Programme de formation" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__link -msgid "Programme détaillé" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.registration_attendee_details_sessions -msgid "Prénom *" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_registration__partner_firstname -msgid "Prénom du participant" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields.selection,name:cgscop_website_event.selection__event_event__type_event_cg__reunion -#: model:ir.model.fields.selection,name:cgscop_website_event.selection__event_type__type_event_cg__reunion -msgid "Réunion d'information" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant__session_id -msgid "Session" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model,name:cgscop_website_event.model_event_session_slot -msgid "Session Slots" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_type__website_session -msgid "Sessions on Website" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_event__website_session -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__website_session -msgid "Sessions sur le site" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.event_event_view_form -msgid "Showcase Sessions" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant__partner_company_name -msgid "Société" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__date_begin -msgid "Start Date" -msgstr "Date de début" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.registration_attendee_details_sessions -msgid "Sélectionner les ateliers auxquels vous voulez participer" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__tag_ids -msgid "Tags" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,help:cgscop_website_event.field_event_session__website_url -msgid "The full URL to access the document through the website." -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.view_event_session_form -msgid "Titre de l'atelier" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_event__type_event_cg -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__type_event_cg -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_type__type_event_cg -msgid "Type d'évènement" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_res_partner_intervenant__partner_phone -msgid "Téléphone" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.registration_attendee_details_sessions -msgid "Téléphone <small>(Optionel)</small>" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.agenda_main_session -msgid "Unpublished" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__website_published -msgid "Visible on current website" -msgstr "" - -#. module: cgscop_website_event -#: model:ir.model,name:cgscop_website_event.model_website_event_menu -msgid "Website Event Menu" -msgstr "Menu des événements du site web" - -#. module: cgscop_website_event -#: model:ir.model,name:cgscop_website_event.model_website_menu -msgid "Website Menu" -msgstr "Menu du site web" - -#. module: cgscop_website_event -#: model:ir.model.fields,field_description:cgscop_website_event.field_event_session__website_url -msgid "Website URL" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.agenda_main -msgid "ateliers" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.event_session_content -msgid "commence" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.event_session_content -msgid "commence à" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.event_session_content -msgid "dans quelques instants" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.event_session_content -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.registration_event_session -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.sessions_display_list -msgid "place(s) restante(s) en pré-inscription" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.event_session_content -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.registration_event_session -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.sessions_display_list -msgid "place(s) restante(s) et" -msgstr "" - -#. module: cgscop_website_event -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.agenda_online -#: model_terms:ir.ui.view,arch_db:cgscop_website_event.sessions_main -msgid "recherche." -msgstr "" - -#. module: website_event -#: model_terms:ir.ui.view,arch_db:website_event.registration_template -msgid "Sales end on" -msgstr "Clôture des inscriptions le" - -#. module: website_event -#: model_terms:ir.ui.view,arch_db:website_event.registration_template -msgid "Ticket Sales starting on" -msgstr "Début des inscriptions le" - - -#. module: website_event -#: model_terms:ir.ui.view,arch_db:website_event.registration_template -msgid "Sales start on" -msgstr "Début des inscriptions le" \ No newline at end of file diff --git a/models/__init__.py b/models/__init__.py index c8082ef8a63a72b2c91ef5448a2e25eadff5346f..ba7bfbee5fd7900d7d2e29a111549093dfa1deaa 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -1,13 +1,3 @@ -# Copyright 2023 Le Filament (https://le-filament.com) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) - from . import event -from . import event_event_ticket from . import event_registration -from . import event_session -from . import event_session_slot -from . import event_tag -from . import event_type -from . import res_partner_intervenant from . import website_event_menu -from . import website_menu diff --git a/models/event.py b/models/event.py index 725a039a310e0206dca9a9c35fab28b0911c717a..bba23c092fc314a723cdb1b7a18aac832f0899f0 100644 --- a/models/event.py +++ b/models/event.py @@ -1,256 +1,106 @@ # Copyright 2023 Le Filament (https://le-filament.com) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) -import re -from odoo import _, api, fields, models - -from odoo.addons.http_routing.models.ir_http import slug +from odoo import api, fields, models class Event(models.Model): _inherit = "event.event" - website_session = fields.Boolean("Sessions sur le site") - session_menu_ids = fields.One2many( - "website.event.menu", - "event_id", - string="Event Session Menus", - domain=[("menu_type", "=", "session")], + hosting_menu = fields.Boolean( + "Menu Hébergement", + compute="_compute_website_menu_data", + readonly=False, + store=True, + ) + hosting_menu_ids = fields.One2many( + comodel_name="website.event.menu", + inverse_name="event_id", + string="Hosting Menus", + domain=[("menu_type", "=", "hosting")], ) - type_event_cg = fields.Selection( - [ - ("agenda", "Agenda"), - ("formation", "Formation"), - ("reunion", "Réunion d'information"), - ], - "Type d'évènement", - default="agenda", + program_menu = fields.Boolean( + "Menu Programme", + compute="_compute_website_menu_data", readonly=False, store=True, - compute="_compute_type_event_cg", - required=True, ) - hide_website_event_title = fields.Boolean( - string="Masquer le titre de l'évènement sur le site web", default=False + program_menu_ids = fields.One2many( + comodel_name="website.event.menu", + inverse_name="event_id", + string="Program Menus", + domain=[("menu_type", "=", "program")], ) # ------------------------------------------------------ # Computed functions # ------------------------------------------------------ - @api.depends("event_type_id") - def _compute_type_event_cg(self): - for event in self: - event.type_event_cg = event.event_type_id.type_event_cg # ------------------------------------------------------ # Onchange / Constraints # ------------------------------------------------------ - @api.onchange("website_menu") - def _onchange_website_session(self): - if not self.website_menu: - self.website_session = False # ------------------------------------------------------ # Action button # ------------------------------------------------------ - def active_sessions(self): - self.ensure_one() - self.use_sessions = not self.use_sessions - if not self.use_sessions: - self.website_session = False - - def action_dup_event_and_web(self): - new_event = self.duplicate_event_and_website({"new_name": self.name}) - return { - "view_type": "form", - "view_mode": "form", - "res_model": "event.event", - "type": "ir.actions.act_window", - "res_id": new_event.id, - } - - def duplicate_event_and_website(self, default_dict: dict = None): - """ - Create a new event along with its website pages - - One view as an inheritance there other one might not if only the title has been changed - If the structure of the view hasn't been changed, the view with inherit_id won't be created - therefore the copy won't happen even if the title only has been changed. - - :param default_dict: - :return: - """ - self.ensure_one() - copied_event = None - if self.website_menu: - # If the name is not provided for the copy then the copied event take the same name as the original event - copied_event = self.copy(default=default_dict) # Copy current event - key_part = f"{slug(self)}" - - views_to_copy = self.env["ir.ui.view"].search( - [("key", "like", key_part), ("inherit_id", "!=", False)] - ) - - for view in views_to_copy: - # Order of creation matter for the later delete - copied_inherited_view = view.inherit_id.copy() - copied_view = view.copy() - - # Replace ids in keys for each view - copied_view.update( - { - "key": self.replace_key_id(copied_view.key, copied_event.id), - "inherit_id": copied_inherited_view.id, - } - ) - copied_inherited_view.update( - { - "key": self.replace_key_id( - copied_inherited_view.key, copied_event.id - ) - } - ) - else: - copied_event = self.copy() - - return copied_event - - def replace_key_id(self, key: str, replace_id: int) -> str: - """ - This method is used to replace the id that has been added - in the key. During the copy process the view will keep the - old reference id, therefore it needs to be changed to the new - one - - :param key (str): the key you want to change the id in - :param replace_id (int): the id you wish the change for - :return (str): the new key - """ - regex = r"(?<=-)[0-9]+" - new_key = re.sub(regex, str(replace_id), key, count=0, flags=re.MULTILINE) - return new_key # ------------------------------------------------------ - # Default functions + # Inherit parent # ------------------------------------------------------ - def _default_cover_properties(self): - res = super()._default_cover_properties() - res.update( - { - "background_color_class": "cg_bc4", - "background-image": "none", - "opacity": "0.2", - "resize_class": "o_half_screen_height", - } - ) - return res - - def toggle_website_session(self, val): - self.website_session = val + @api.depends("website_menu") + def _compute_website_menu_data(self): + super()._compute_website_menu_data() + for event in self: + event.hosting_menu = event.website_menu + event.program_menu = event.website_menu def _get_menu_update_fields(self): - return super()._get_menu_update_fields() + ["website_session"] + res = super()._get_menu_update_fields() + return res + ["hosting_menu", "program_menu"] + + def _get_menu_type_field_matching(self): + res = super()._get_menu_type_field_matching() + res["hosting"] = "hosting_menu" + res["program"] = "program_menu" + return res + + def _get_website_menu_entries(self): + res = super()._get_website_menu_entries() + [ + ( + "Hébergement", + False, + "cgscop_website_event.template_hosting", + 60, + "hosting", + ), + ( + "Programme", + False, + "cgscop_website_event.template_program", + 70, + "program", + ), + ] + return res def _update_website_menus(self, menus_update_by_field=None): - record = super()._update_website_menus( - menus_update_by_field=menus_update_by_field - ) + super()._update_website_menus(menus_update_by_field=menus_update_by_field) for event in self: if event.menu_id and ( not menus_update_by_field - or event in menus_update_by_field.get("website_session") + or event in menus_update_by_field.get("hosting_menu") ): event._update_website_menu_entry( - "website_session", "session_menu_ids", "session" + "hosting_menu", "hosting_menu_ids", "hosting" + ) + if event.menu_id and ( + not menus_update_by_field + or event in menus_update_by_field.get("program_menu") + ): + event._update_website_menu_entry( + "program_menu", "program_menu_ids", "program" ) - - return record - - def _get_website_menu_entries(self): - self.ensure_one() - return super()._get_website_menu_entries() + [ - (_("Ateliers"), "/event/%s/session" % slug(self), False, 10, "session"), - ( - _("Calendrier"), - "/event/%s/agenda-sessions" % slug(self), - False, - 10, - "session", - ), - ] # ------------------------------------------------------ # CRUD methods (ORM overrides) # ------------------------------------------------------ - - @api.returns("self", lambda value: value.id) - def copy_data(self, default: dict = None) -> [dict]: - """ - Inheritance of copy_data() from models module in order to counter the spread of - event 'copy' string when an event is copied. - - :param default: The default dict containing fields and their value for the copy - :return: A list of dictionnary (default) that key will be used as fields during the copy process - """ - self.ensure_one() - if default.get("new_name"): - default["name"] = default["new_name"] - default.pop("new_name") - return super().copy_data(default) - - @api.ondelete(at_uninstall=True) - def _flush_website_event_menus_and_views(self): - for event in self: - if event.website_menu: - website_menu_events = self.env["website.event.menu"].search( - [("event_id", "=", event.id)] - ) - - menus = [] - key = None - for website_menu_event in website_menu_events: - menus.append(website_menu_event.menu_id) - if key is None and website_menu_event.view_id.key: - key = website_menu_event.view_id.key - key = "-".join(key.split(".")[1].split("-")[1:]) - - menu_parents = {menu.parent_id for menu in menus} - for parent in menu_parents: - parent.unlink() - - if key: - views = self.env["ir.ui.view"].search( - [("key", "like", key)], order="id" - ) - view_list = [view for view in views] - view_list.reverse() - - for view in view_list: - view.unlink() - - def _create_menu(self, sequence, name, url, xml_id, menu_type): - """ - Ensure the menu is created with the right view. Before this override the menus were referencing a wrong view - For 2 website events with the same name for instance "golf-tournament", two views were created, golf-tournament - and golf-tournament-1 - The second view whould never be called because the menu of the second website_event would refer to the view of - the first website_event and not of the second - - This behaviour has been identified of use of key which has no unicity constraint. - """ - website_menu = super()._create_menu(sequence, name, url, xml_id, menu_type) - - website_event_menu = ( - self.env["website.event.menu"] - .sudo() - .search([("menu_id", "=", website_menu.id)]) - ) - view_id = website_event_menu.view_id - if view_id: - view_id.update({"key": f"{view_id.key}-{self.id}"}) - key = view_id.key.split(".")[1] - url_splitted = website_menu.url.split("/") - url_splitted[-1] = key - - website_menu.update({"url": "/".join(url_splitted)}) - return website_menu diff --git a/models/event_event_ticket.py b/models/event_event_ticket.py deleted file mode 100644 index d3772af15b4108a6dd084925087ffd7e7c2c0351..0000000000000000000000000000000000000000 --- a/models/event_event_ticket.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2023 Le Filament (<http://www.le-filament.com>) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -from odoo import api, models - - -class EventEventTicket(models.Model): - _inherit = "event.event.ticket" - - # ------------------------------------------------------ - # Fields declaration - # ------------------------------------------------------ - - # ------------------------------------------------------ - # SQL Constraints - # ------------------------------------------------------ - - # ------------------------------------------------------ - # Default methods - # ------------------------------------------------------ - - # ------------------------------------------------------ - # Computed fields / Search Fields - # ------------------------------------------------------ - @api.depends("seats_max", "registration_ids.state", "registration_ids.active") - def _compute_seats(self): - # Ajout des réservations non confirmées dans le compte des tickets dispos - super(EventEventTicket, self)._compute_seats() - - for ticket in self: - if ticket.seats_max > 0: - ticket.seats_available = ( - ticket.seats_available - ticket.seats_unconfirmed - ) - - # ------------------------------------------------------ - # Onchange / Constraints - # ------------------------------------------------------ - - # ------------------------------------------------------ - # CRUD methods (ORM overrides) - # ------------------------------------------------------ - - # ------------------------------------------------------ - # Actions - # ------------------------------------------------------ - - # ------------------------------------------------------ - # Business methods - # ------------------------------------------------------ diff --git a/models/event_registration.py b/models/event_registration.py index 6d752b8f6e532101d5647411d6250253e80ca55a..547e96ae224856a7c3faf7c65be4b07298a95e1d 100644 --- a/models/event_registration.py +++ b/models/event_registration.py @@ -5,7 +5,7 @@ from odoo import api, fields, models class EventRegistration(models.Model): - _inherit = ["event.registration"] + _inherit = "event.registration" partner_lastname = fields.Char("Nom du participant") partner_firstname = fields.Char("Prénom du participant") @@ -37,25 +37,3 @@ class EventRegistration(models.Model): "partner_id", "event_ticket_id", } - - def get_sessions_by_mail(self): - self.ensure_one() - # Permet de récupérer toutes les inscriptions aux ateliers pour un même mail - registration_ids = self.env["event.registration"].search( - [ - ("event_id", "=", self.event_id.id), - ("session_id", "!=", False), - ("email", "=", self.email), - ] - ) - return registration_ids.mapped("session_id").sorted("date_begin") - - def action_send_badge_email(self): - """Open a window to compose an email, with the template - 'event_badge' - message loaded by default - """ - self.ensure_one() - result = super(EventRegistration, self).action_send_badge_email() - if result.get("context") and result["context"].get("default_template_id"): - result["context"]["default_template_id"] = False - return result diff --git a/models/event_session.py b/models/event_session.py deleted file mode 100644 index bcc66e3ee90d3f059fa1b5327f4cebdbe8c52a68..0000000000000000000000000000000000000000 --- a/models/event_session.py +++ /dev/null @@ -1,224 +0,0 @@ -# Copyright 2023 Le Filament (<http://www.le-filament.com>) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -from datetime import datetime -from random import randint - -from dateutil.relativedelta import relativedelta - -from odoo import api, fields, models -from odoo.osv import expression - -from odoo.addons.http_routing.models.ir_http import slug - - -class EventSession(models.Model): - _name = "event.session" - _inherit = ["event.session", "website.published.mixin"] - - # ------------------------------------------------------ - # Default values - # ------------------------------------------------------ - @api.model - def _get_default_tags(self): - if self.env.context.get("default_event_id"): - event_id = self.env["event.event"].browse( - self.env.context.get("default_event_id") - ) - if event_id.tag_ids: - return [(6, 0, event_id.tag_ids.ids)] - - # ------------------------------------------------------ - # Fields declaration - # ------------------------------------------------------ - date_begin = fields.Datetime( - string="Start Date", - required=True, - default=datetime.today(), - ) - date_end = fields.Datetime( - string="End Date", - required=True, - default=datetime.today() + relativedelta(hours=1), - ) - session_name = fields.Char("Nom de l'atelier") - - seats_min = fields.Integer(string="Nombre minimum de participants") - - seats_available_unconfirmed = fields.Integer( - string="Places disponibles en pré-inscription", - compute="_compute_seats_available_unconfirmed", - store=True, - ) - seats_max = fields.Integer("Nombre maximal de participants") - - intervenant_ids = fields.One2many( - "res.partner.intervenant", "session_id", string="Intervenants" - ) - - description = fields.Text("Description de l'atelier") - - duration = fields.Float("Durée", default=1.5, compute="_compute_duration") - duration_slot = fields.Float( - "Durée des créneaux", compute="_compute_duration_slot", store=True - ) - color = fields.Integer("Couleur") - - event_session_slot_ids = fields.One2many( - "event.session.slot", "session_id", "Créneaux des ateliers", required=True - ) - - tag_ids = fields.Many2many("event.tag", string="Tags", default=_get_default_tags) - - link = fields.Char("Programme détaillé") - link_auto_eval = fields.Char("Fiche Auto Evaluation") - - event_session_registrations_sold_out = fields.Boolean( - "Atelier Complet", - compute="_compute_event_session_registrations_sold_out", - compute_sudo=True, - ) - # Override parent fields - event_mail_ids = fields.One2many( - compute=False, - ) - - # ------------------------------------------------------ - # SQL Constraints - # ------------------------------------------------------ - - # ------------------------------------------------------ - # Default methods - # ------------------------------------------------------ - - # ------------------------------------------------------ - # Computed fields / Search Fields - # ------------------------------------------------------ - @api.depends("date_begin_located", "date_tz", "session_name") - def _compute_display_name(self): - with_event_name = self.env.context.get("with_event_name", True) - for rec in self: - name = f"{rec.session_name}, " if with_event_name else "" - name += rec.date_begin_located - if rec.date_tz != self.env.user.tz: - name += f" ({rec.date_tz})" - rec.display_name = name - - @api.depends("date_begin", "date_end") - def _compute_duration(self): - for session in self: - if session.date_begin and session.date_end: - session.duration = ( - session.date_end - session.date_begin - ).total_seconds() / 3600 - else: - session.duration = 0.0 - - @api.depends("event_session_slot_ids", "event_session_slot_ids.duration") - def _compute_duration_slot(self): - for session in self: - duration = 0.0 - for slot in session.event_session_slot_ids: - duration += slot.duration - session.duration_slot = duration - - @api.depends("name") - def _compute_website_url(self): - super(EventSession, self)._compute_website_url() - for session in self: - if session.id: - session.website_url = "/event/%s/session/%s" % ( - slug(session.event_id), - slug(session), - ) - - @api.depends("seats_unconfirmed", "seats_reserved", "seats_used", "seats_max") - def _compute_seats_available_unconfirmed(self): - # Ajout des réservations non confirmées - super(EventSession, self)._compute_seats_available() - for rec in self: - rec.seats_available_unconfirmed = ( - rec.seats_max - - (rec.seats_reserved + rec.seats_used + rec.seats_unconfirmed) - if rec.seats_max > 0 - else 0 - ) - - @api.depends("event_ticket_ids.sale_available", "seats_available", "seats_limited") - def _compute_event_session_registrations_sold_out(self): - """Note that max seats limits for events session - and sum of limits for all its tickets may not be - equal to enable flexibility. - E.g. max 20 seats for ticket A, 20 seats for ticket B - * With max 20 seats for the event - * Without limit set on the event - (=40, but the customer didn't explicitly write 40) - """ - for session in self: - session.event_session_registrations_sold_out = ( - session.seats_max and not session.seats_available - ) or ( - session.event_ticket_ids - and all(ticket.is_sold_out for ticket in session.event_ticket_ids) - ) - - # ------------------------------------------------------ - # Onchange / Constraints - # ------------------------------------------------------ - - # ------------------------------------------------------ - # CRUD methods (ORM overrides) - # ------------------------------------------------------ - - # ------------------------------------------------------ - # Actions - # ------------------------------------------------------ - - def get_backend_menu_id(self): - return self.env.ref("event.event_main_menu").id - - # ------------------------------------------------------ - # Business methods - # ------------------------------------------------------ - def _get_session_suggestions(self, restrict_domain=None, limit=None): - """Returns the next tracks suggested after going to the current one - given by self. Tracks always belong to the same event. - - Heuristic is - - * live first; - * then ordered by start date, finished being sent to the end; - * wishlisted (manually or by default); - * tag matching with current track; - * location matching with current track; - * finally a random to have an "equivalent wave" randomly given; - - :param restrict_domain: an additional domain to restrict candidates; - :param limit: number of tracks to return; - """ - self.ensure_one() - - base_domain = [ - "&", - ("event_id", "=", self.event_id.id), - ("id", "!=", self.id), - ] - if restrict_domain: - base_domain = expression.AND([base_domain, restrict_domain]) - - session_candidates = self.search( - base_domain, limit=None, order="date_begin asc" - ) - if not session_candidates: - return session_candidates - - session_candidates = session_candidates.sorted( - lambda session: ( - session.is_published, - session.date_begin, - randint(0, 20), - ), - reverse=True, - ) - - return session_candidates[:limit] diff --git a/models/event_session_slot.py b/models/event_session_slot.py deleted file mode 100644 index 10115bb83c411301e40895fda641b4f1867fc1d8..0000000000000000000000000000000000000000 --- a/models/event_session_slot.py +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright 2023 Le Filament (<http://www.le-filament.com>) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -from odoo import api, fields, models - - -class SessionSlot(models.Model): - """Table linking session and slots.""" - - _name = "event.session.slot" - _description = "Session Slots" - - session_id = fields.Many2one( - "event.session", string="Atelier", index=True, required=True, ondelete="cascade" - ) - date = fields.Datetime("Date de début de créneau") - date_end = fields.Datetime("Date de fin de créneau") - duration = fields.Float( - "Durée", default=0.5, compute="_compute_duration", store=True - ) - # ------------------------------------------------------ - # SQL Constraints - # ------------------------------------------------------ - - # ------------------------------------------------------ - # Default methods - # ------------------------------------------------------ - - # ------------------------------------------------------ - # Computed fields / Search Fields - # ------------------------------------------------------ - @api.depends("date", "date_end") - def _compute_duration(self): - for slot in self: - if slot.date and slot.date_end: - slot.duration = (slot.date_end - slot.date).total_seconds() / 3600 - else: - slot.duration = 0.0 - - # ------------------------------------------------------ - # Onchange / Constraints - # ------------------------------------------------------ - - # ------------------------------------------------------ - # CRUD methods (ORM overrides) - # ------------------------------------------------------ - @api.model_create_multi - def create(self, vals_list): - session_slots = super(SessionSlot, self).create(vals_list) - # Update date min and max on session linked - for session_slot in session_slots: - date_min = ( - self.env["event.session.slot"] - .search( - [("session_id", "=", session_slot.session_id.id)], - limit=1, - order="date ASC", - ) - .date - ) - date_max = ( - self.env["event.session.slot"] - .search( - [("session_id", "=", session_slot.session_id.id)], - limit=1, - order="date_end DESC", - ) - .date_end - ) - session_slot.session_id.write( - { - "date_begin": date_min, - "date_end": date_max, - } - ) - - return session_slots - - def write(self, vals): - res = super(SessionSlot, self).write(vals) - # Update date min and max on session linked - for session_slot in self: - date_min = ( - self.env["event.session.slot"] - .search( - [("session_id", "=", session_slot.session_id.id)], - limit=1, - order="date ASC", - ) - .date - ) - date_max = ( - self.env["event.session.slot"] - .search( - [("session_id", "=", session_slot.session_id.id)], - limit=1, - order="date_end DESC", - ) - .date_end - ) - session_slot.session_id.write( - { - "date_begin": date_min, - "date_end": date_max, - } - ) - - return res - - # ------------------------------------------------------ - # Actions - # ------------------------------------------------------ - - # ------------------------------------------------------ - # Business methods - # ------------------------------------------------------ diff --git a/models/event_tag.py b/models/event_tag.py deleted file mode 100644 index 8ea0a8c47061510f803f227a1796fe8e7c974de9..0000000000000000000000000000000000000000 --- a/models/event_tag.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2023 Le Filament (<http://www.le-filament.com>) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - - -from odoo import fields, models - - -class EventTagCategory(models.Model): - _inherit = "event.tag.category" - - company_id = fields.Many2one( - "res.company", - string="Company", - change_default=True, - default=lambda self: self.env.company, - required=False, - ) - - -class EventTag(models.Model): - _inherit = "event.tag" - - company_id = fields.Many2one( - "res.company", - string="Company", - change_default=True, - default=lambda self: self.env.company, - required=False, - ) diff --git a/models/event_type.py b/models/event_type.py deleted file mode 100644 index a810e15bf21475765963f3ae45b02f48c38fa1a1..0000000000000000000000000000000000000000 --- a/models/event_type.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2023 Le Filament (<http://www.le-filament.com>) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -from odoo import api, fields, models - - -class EventType(models.Model): - _inherit = "event.type" - - website_session = fields.Boolean( - string="Sessions on Website", - compute="_compute_website_session_menu_data", - readonly=False, - store=True, - ) - - type_event_cg = fields.Selection( - [ - ("agenda", "Agenda"), - ("formation", "Formation"), - ("reunion", "Réunion d'information"), - ], - string="Type d'évènement", - default="agenda", - required=True, - ) - - @api.depends("website_menu") - def _compute_website_session_menu_data(self): - """Simply activate or de-activate all menus at once.""" - for event_type in self: - event_type.website_session = event_type.website_menu diff --git a/models/res_partner_intervenant.py b/models/res_partner_intervenant.py deleted file mode 100644 index 7b490da6b66643347fc793d6ae39c3a17263a193..0000000000000000000000000000000000000000 --- a/models/res_partner_intervenant.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2023 Le Filament (<http://www.le-filament.com>) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -from odoo import api, fields, models - - -class ResPartnerIntervenant(models.Model): - _name = "res.partner.intervenant" - _description = "Intervenants" - - # ------------------------------------------------------ - # Fields declaration - # ------------------------------------------------------ - partner_id = fields.Many2one("res.partner", "Intervenant") - partner_name = fields.Char( - string="Nom de l'intervenant", - compute="_compute_partner", - readonly=False, - store=True, - ) - partner_email = fields.Char( - string="Mail", - compute="_compute_partner", - readonly=False, - store=True, - ) - partner_phone = fields.Char( - string="Téléphone", - compute="_compute_partner", - readonly=False, - store=True, - ) - partner_description = fields.Char(string="Description de l'intervenant") - partner_function = fields.Char( - "Fonction", related="partner_id.function", compute_sudo=True, readonly=True - ) - partner_company_name = fields.Char( - "Société", related="partner_id.parent_name", compute_sudo=True, readonly=True - ) - session_id = fields.Many2one("event.session", "Session") - - # ------------------------------------------------------ - # SQL Constraints - # ------------------------------------------------------ - - # ------------------------------------------------------ - # Default methods - # ------------------------------------------------------ - - # ------------------------------------------------------ - # Computed fields / Search Fields - # ------------------------------------------------------ - @api.depends("partner_id") - def _compute_partner(self): - for partner in self: - if not partner.partner_name or partner.partner_id: - partner.partner_name = partner.partner_id.name - if not partner.partner_email or partner.partner_id: - partner.partner_email = partner.partner_id.email - if not partner.partner_phone or partner.partner_id: - partner.partner_phone = partner.partner_id.phone - - # ------------------------------------------------------ - # Onchange / Constraints - # ------------------------------------------------------ - - # ------------------------------------------------------ - # CRUD methods (ORM overrides) - # ------------------------------------------------------ - - # ------------------------------------------------------ - # Actions - # ------------------------------------------------------ - - # ------------------------------------------------------ - # Business methods - # ------------------------------------------------------ diff --git a/models/website_event_menu.py b/models/website_event_menu.py index 338bd4d1df12951566f4b46f27c231b79e163860..b8ba30c2e7d7253d4158bcda933e8a4f06ace7d0 100644 --- a/models/website_event_menu.py +++ b/models/website_event_menu.py @@ -8,6 +8,6 @@ class EventMenu(models.Model): _inherit = "website.event.menu" menu_type = fields.Selection( - selection_add=[("session", "Event Sessions Menus")], - ondelete={"session": "cascade"}, + selection_add=[("hosting", "Hébergement"), ("program", "Programme")], + ondelete={"hosting": "cascade", "program": "cascade"}, ) diff --git a/models/website_menu.py b/models/website_menu.py deleted file mode 100644 index 586a8e9b6227de0de73456fb70ef40aa3e03a4c3..0000000000000000000000000000000000000000 --- a/models/website_menu.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2023 Le Filament (<http://www.le-filament.com>) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -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()) - # specifically check for /track in menu URL; - # to avoid unchecking track field when removing - # agenda page that has also menu_type='track' - if ( - event_menu.menu_type == "session" - and "/session" in event_menu.menu_id.url - ): - to_update.append("website_session") - - # 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({fname: False for fname in to_update}) - - return res diff --git a/static/src/js/website_event_session.js b/static/src/js/website_event_session.js deleted file mode 100644 index d037834c743063a9ed8e73afdc77bb235a918c17..0000000000000000000000000000000000000000 --- a/static/src/js/website_event_session.js +++ /dev/null @@ -1,54 +0,0 @@ -odoo.define("cgscop_website_event.website_event_session", function (require) { - "use strict"; - - var publicWidget = require("web.public.widget"); - - publicWidget.registry.websiteEventSession = publicWidget.Widget.extend({ - selector: ".o_wevent_event", - events: { - "input #event_session_search": "_onEventSessionSearchInput", - }, - - // -------------------------------------------------------------------------- - // Handlers - // -------------------------------------------------------------------------- - - /** - * @override - */ - start: function () { - this._super.apply(this, arguments).then(() => { - this.$el.find('[data-bs-toggle="popover"]').popover(); - }); - }, - - /** - * @private - * @param {Event} ev - */ - _onEventSessionSearchInput: function (ev) { - ev.preventDefault(); - var text = $(ev.currentTarget).val(); - var $sessions = $(".event_session"); - - // Check if the user is performing a search; i.e., text is not empty - if (text) { - function filterSessions(index, element) { - // When filtering elements only check the text content - return this.textContent.toLowerCase().includes(text.toLowerCase()); - } - $("#search_summary").removeClass("invisible"); - $("#search_number").text($sessions.filter(filterSessions).length); - - $sessions - .removeClass("invisible") - .not(filterSessions) - .addClass("invisible"); - } else { - // If no search is being performed; hide the result count text - $("#search_summary").addClass("invisible"); - $sessions.removeClass("invisible"); - } - }, - }); -}); diff --git a/static/src/scss/cgscop_website_event.scss b/static/src/scss/cgscop_website_event.scss deleted file mode 100644 index 4f1ce2547cabc98aa90547ef81f72858c4ebb5e8..0000000000000000000000000000000000000000 --- a/static/src/scss/cgscop_website_event.scss +++ /dev/null @@ -1,191 +0,0 @@ -// Index -.tc1 { - color: #93134e !important; -} -.cg_bc1 { - background-color: #93134e !important; - color: #fff !important; -} -.cg_tc2 { - color: #a72758 !important; -} -.cg_tc3 { - color: #bd3562 !important; -} -.cg_bc3 { - background-color: #bd3562 !important; - color: #fff !important; -} -.cg_tc4 { - color: #d3426b !important; -} -.cg_bc4 { - background-color: #d3426b !important; - color: #fff !important; -} -.cg_tc5 { - color: #e5074d !important; -} -.cg_bc5 { - background-color: #e5074d !important; - color: #fff !important; -} - -/* - * AGENDA sessions - */ - -.o_weagenda_index { - hr { - border-color: lighten($o-wevent-bg-color-base-contrast, 50%); - } -} - -.o_we_online_agenda { - overflow-x: auto; - table { - border-collapse: separate; - border-spacing: 0em 0em; - tr { - height: 15px; - line-height: 1em; - &.active { - td.active { - padding: 0em 0.5em; - font-size: smaller; - border-top: 1px solid lighten($o-wevent-bg-color-base-contrast, 50%); - } - } - } - th.active, - td:not(.active) { - border: 0px; - border-right: 1em solid $body-bg; - vertical-align: middle; - span { - word-break: break-word; - } - } - th:not(.active), - td.active { - width: 100px; - } - th.position-sticky { - left: 0; - } - td { - border: 0px; - - @for $size from 1 through 20 { - @if #{$size} != 1 { - &.o_location_size_#{$size} { - width: calc(100% / (#{$size} - 1)); - min-width: 150px; - } - } @else { - width: calc(100%); - } - } - - &.active { - z-index: 1; - position: sticky; - left: 0; - min-width: 100px; - } - div.o_we_agenda_card_content { - height: 100%; - .o_we_agenda_card_title, - small { - word-break: break-word; - } - .badge:hover { - cursor: pointer; - } - } - .badge { - height: fit-content; - max-width: 100%; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - font-size: xx-small; - padding: 0.2em 0.5em; - border-radius: 1em; - line-height: 10px; - } - &.invisible { - visibility: visible !important; - opacity: 0.3; - } - &.o_we_agenda_time_slot_main, - &.o_we_agenda_time_slot_half { - padding: 0; - position: relative; - > div { - position: absolute; - top: 0; - width: 100%; - } - } - &.o_we_agenda_time_slot_main > div { - padding: 0.3em; - border-top: 1px solid lighten($o-wevent-bg-color-base-contrast, 50%); - } - &.o_we_agenda_time_slot_half > div { - padding: 0.3em; - border-top: 1px dashed lighten($o-wevent-bg-color-base-contrast, 50%); - } - &.event_track { - position: relative; - padding: 0; - &::before { - content: ""; - display: block; - width: 100%; - position: absolute; - top: 0; - border-top: 1px solid lighten($o-wevent-bg-color-base-contrast, 50%); - } - &::after { - content: ""; - display: block; - width: 100%; - position: absolute; - bottom: 0; - border-bottom: 1px solid - lighten($o-wevent-bg-color-base-contrast, 50%); - margin-bottom: -1px; - z-index: 1; - } - > div { - padding: 0.3em; - } - // For unpublished tracks, opacity is already reduced - [data-publish="off"] - .o_weagenda_track_badges - > .o_wevent_online_badge_unpublished { - opacity: unset; - } - } - } - } -} - -/* - * EVENT TOOL: DATE - */ -.o_wevent_event { - .o_we_track_day_header { - & > div > span.h1 { - font-size: xx-large; - } - a.collapsed { - transform: rotate(-90deg); - } - } -} - -.modal-content .o_wevent_event { - min-height: auto; -} diff --git a/templates/hosting.xml b/templates/hosting.xml new file mode 100644 index 0000000000000000000000000000000000000000..b30a97f4edd626c9dccbe9416ca9c105b34aef97 --- /dev/null +++ b/templates/hosting.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <template id="template_hosting"> + <t t-call="website_event.layout"> + <div class="oe_structure oe_empty" id="oe_structure_website_event_program_1"/> + <section class="s_title pt32 pb32" data-vcss="001" data-snippet="s_title" data-name="Title"> + <div class="container s_allow_columns"> + <h1 class="text-center"> + <font style="font-size: 62px;" class="o_default_snippet_text">Introduction</font> + </h1> + </div> + </section> + <div class="oe_structure oe_empty" id="oe_structure_website_event_program_2"/> + </t> + </template> +</odoo> diff --git a/templates/page_registration.xml b/templates/page_registration.xml new file mode 100644 index 0000000000000000000000000000000000000000..8ba8e7ee7c23dd6ffdee4adbe8811874d4999bf4 --- /dev/null +++ b/templates/page_registration.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8" ?> +<odoo> + + <template + id="registration_attendee_details" + inherit_id="website_event.registration_attendee_details" + name="Registration Attendee Details with firstname" + priority="20" + > + <div class="row" position="replace"> + <div class="row"> + <div class="col-lg my-2"> + <label>Nom *</label> + <input + class="form-control" + type="text" + t-attf-name="#{counter}-partner_lastname" + required="Ce champ ets obligatoire" + t-att-value="default_first_attendee.get('partner_lastname', '') if counter == 1 else ''" + /> + </div><div class="col-lg my-2"> + <label>Prénom *</label> + <input + class="form-control" + type="text" + t-attf-name="#{counter}-partner_firstname" + required="Ce champ ets obligatoire" + t-att-value="default_first_attendee.get('partner_firstname', '') if counter == 1 else ''" + /> + </div> + <div class="col-lg my-2"> + <label>Mail *</label> + <input + class="form-control" + type="email" + t-attf-name="#{counter}-email" + required="Ce champ ets obligatoire" + t-att-value="default_first_attendee.get('email', '') if counter == 1 else ''" + /> + </div> + <div class="col-lg my-2"> + <label>Téléphone <small>(Optionel)</small></label> + <input + class="form-control" + type="tel" + t-attf-name="#{counter}-phone" + t-att-value="default_first_attendee.get('phone', '') if counter == 1 else ''" + /> + </div> + <input + class="d-none" + type="text" + t-attf-name="#{counter}-event_ticket_id" + t-attf-value="#{ticket['id']}" + /> + </div> + </div> + </template> + + +</odoo> diff --git a/templates/program.xml b/templates/program.xml new file mode 100644 index 0000000000000000000000000000000000000000..3fd3f14f43c10ee36e2c13dea34daf37725f046e --- /dev/null +++ b/templates/program.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <template id="template_program"> + <t t-call="website_event.layout"> + <div class="oe_structure oe_empty" id="oe_structure_website_event_program_1"/> + <section class="s_title pt32 pb32" data-vcss="001" data-snippet="s_title" data-name="Title"> + <div class="container s_allow_columns"> + <h1 class="text-center"> + <font style="font-size: 62px;" class="o_default_snippet_text">Introduction</font> + </h1> + </div> + </section> + <div class="oe_structure oe_empty" id="oe_structure_website_event_program_2"/> + </t> + </template> +</odoo> diff --git a/views/event_registration_views.xml b/views/event_registration_views.xml new file mode 100644 index 0000000000000000000000000000000000000000..3a685acc5d094eea205b13fa82a4e4d56acd0a2f --- /dev/null +++ b/views/event_registration_views.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8" ?> +<odoo> + + <record id="view_event_registration_form" model="ir.ui.view"> + <field name="name">scop.event.registration.view.from.inherit</field> + <field name="inherit_id" ref="event.view_event_registration_form" /> + <field name="model">event.registration</field> + <field name="priority" eval="10" /> + <field name="arch" type="xml"> + <xpath expr="//field[@name='name']" position="attributes"> + <attribute name="string">Nom Complet</attribute> + <attribute name="readonly">1</attribute> + </xpath> + <xpath expr="//field[@name='name']" position="after"> + <field name="partner_lastname" /> + <field name="partner_firstname" /> + </xpath> + </field> + </record> + + <record id="view_event_registration_tree" model="ir.ui.view"> + <field name="name">scop.event.registration.view.tree.inherit</field> + <field name="inherit_id" ref="event.view_event_registration_tree" /> + <field name="model">event.registration</field> + <field name="priority" eval="10" /> + <field name="arch" type="xml"> + <xpath expr="//field[@name='name']" position="attributes"> + <attribute name="string">Nom Complet</attribute> + </xpath> + <xpath expr="//field[@name='name']" position="after"> + <field name="partner_lastname" /> + <field name="partner_firstname" /> + </xpath> + </field> + </record> +</odoo> diff --git a/views/event_session_agenda_templates.xml b/views/event_session_agenda_templates.xml deleted file mode 100644 index cd4850346eebbf2304fd4a32ee0a6cccb94d55ac..0000000000000000000000000000000000000000 --- a/views/event_session_agenda_templates.xml +++ /dev/null @@ -1,275 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<odoo> - -<!-- Revamped agenda : Will need to replace agenda_online from website_event_track in master --> -<template id="agenda_online" name="Atelier: Agenda"> - <t t-call="website_event.layout"> - <!-- No Sessions --> - <div t-if="not sessions_by_days" class="container"> - <div class="h2 mb-3">Pas d'ateliers trouvés.</div> - <div t-if="search_key" class="alert alert-info text-center"> - <p class="m-0">Il n'y a pas d'ateliers correspondant à votre <strong - t-out="search_key" - /> recherche.</p> - </div> - </div> - - <div t-else="" class="o_wevent_online o_weagenda_index"> - <!-- Topbar --> - <t t-call="cgscop_website_event.agenda_topbar" /> - <!-- Drag/Drop Area --> - <div - class="oe_structure" - id="oe_structure_website_event_session_agenda_1" - /> - <!-- Content --> - <div class="container-fluid"> - <div class="row mb-5"> - <t t-call="cgscop_website_event.agenda_main" /> - </div> - </div> - <!-- Drag/Drop Area --> - <div - class="oe_structure" - id="oe_structure_website_event_session_agenda_2" - /> - </div> - </t> -</template> - -<!-- ============================================================ --> -<!-- TOPBAR: BASE NAVIGATION --> -<!-- ============================================================ --> - -<!-- Main topbar --> -<template id="agenda_topbar" name="Agenda Tools"> - <nav class="navbar navbar-light border-top shadow-sm d-print-none"> - <div class="container-fluid"> - <div class="d-flex flex-column flex-sm-row justify-content-between w-100"> - <ul class="o_weagenda_topbar_filters o_wevent_index_topbar_filters nav"> - </ul> - <div class="d-flex ps-sm-3 pe-0"> - <label class="invisible text-muted me-2" id="search_summary"><span - id="search_number" - class="me-1" - >0</span>Resultats</label> - <input - type="text" - class="form-control" - placeholder="Filtrer les ateliers..." - id="event_session_search" - /> - </div> - </div> - </div> - </nav> -</template> - -<!-- Option: Topbar: optional tags filters--> -<template - id="agenda_session_topbar_tag" - inherit_id="cgscop_website_event.agenda_topbar" - name="Filtrer par Tags" - active="True" - > - <xpath expr="//ul[hasclass('o_weagenda_topbar_filters')]" position="inside"> - <t t-foreach="tag_categories" t-as="tag_category"> - <li - t-if="tag_category.tag_ids and any(tag.color for tag in tag_category.tag_ids)" - class="nav-item dropdown me-2 my-1" - > - <a - href="#" - role="button" - class="btn dropdown-toggle" - data-bs-toggle="dropdown" - > - <i class="fa fa-folder-open" /> - <t t-out="tag_category.name" /> - </a> - <div class="dropdown-menu"> - <t t-foreach="tag_category.tag_ids" t-as="tag"> - <a - t-att-href="'/event/%s/agenda-sessions?%s' % ( - slug(event), - keep_query('*', tags=str((search_tags - tag).ids if tag in search_tags else (tag | search_tags).ids)) - )" - t-if="tag.color" - t-attf-class="dropdown-item d-flex align-items-center justify-content-between #{'active' if tag in search_tags else ''}" - > - <t t-out="tag.name" /> - </a> - </t> - </div> - </li> - </t> - </xpath> -</template> - -<!-- ============================================================ --> -<!-- CONTENT: MAIN TEMPLATES --> -<!-- ============================================================ --> - -<!-- Agenda Main Display --> -<template id="agenda_main" name="Sessions: Main Display"> - <section t-foreach="days" t-as="day" class="col-12"> - <!-- DAY HEADER --> - <div - class="o_we_session_day_header mt-3 w-100 d-flex justify-content-between align-items-center" - > - <div class="d-flex"> - <span - class="h1 m-0 fw-bold" - t-out="day" - t-options="{'widget': 'date', 'format': 'EEEE dd'}" - /> - <div class="d-flex flex-column ms-2"> - <span - class="fw-bold" - t-out="day" - t-options="{'widget': 'date', 'format': 'MMMM'}" - /> - <span - class="fw-bold" - t-out="day" - t-options="{'widget': 'date', 'format': 'YYYY'}" - /> - </div> - <div class="flex-column align-self-center ms-2"> - <span class="small fw-light">(<t t-out="event.date_tz" />)</span> - </div> - </div> - <small class="float-end text-muted align-self-end"><t - t-out="sessions_by_days[day]" - /> ateliers</small> - </div> - <hr class="mt-2 mb-2" /> - - <!-- Day Agenda --> - <div class="o_we_online_agenda"> - <table id="table_search" class="table table-sm border-0 h-100"> - - <!-- Time Slots --> - <t t-set="used_cells" t-value="[]" /> - <t t-foreach="time_slots[day]" t-as="time_slot"> - <t - t-set="is_round_hour" - t-value="time_slot == time_slot.replace(minute=0)" - /> - <t - t-set="is_half_hour" - t-value="time_slot == time_slot.replace(minute=30)" - /> - - <tr t-att-class="'%s' % ('active' if is_round_hour else '')"> - <td class="active"> - <b - t-if="is_round_hour" - t-out="time_slots[day][time_slot]['formatted_time']" - /> - </td> - - <t t-set="sessions" t-value="time_slots[day].get(time_slot, {})" /> - <t t-if="sessions"> - <t t-foreach="sessions" t-as="session"> - <t t-if="'formatted_time' in session"> - </t> - <t t-else=""> - <t - t-set="_classes" - t-value="'text-center %s %s' % ( - 'event_color_%s' % (session.color or 0), - 'event_session h-100' if session else '', - )" - /> - <td - t-att-rowspan="sessions[session]['rowspan']" - t-att-class="_classes" - > - <t - t-call="cgscop_website_event.agenda_main_session" - /> - </td> - <t - t-set="used_cells" - t-value="used_cells + sessions[session]['occupied_cells']" - /> - </t> - </t> - </t> - <t t-elif="(time_slot) not in used_cells"> - <td - t-att-rowspan="1" - t-att-class="'o_location_size %s' % ( - 'o_we_agenda_time_slot_half' if is_half_hour else - 'o_we_agenda_time_slot_main' if is_round_hour else - '' - )" - ><div /></td> - </t> - </tr> - </t> - </table> - </div> - </section> -</template> - -<template id="agenda_main_session" name="Session Agenda: Session"> - <div - class="d-flex flex-column h-100" - t-att-data-publish="session.website_published and 'on' or 'off'" - > - <div - class="d-flex justify-content-end flex-wrap-reverse align-items-center o_weagenda_track_badges" - > - <small - t-if="not session.website_published and is_event_user" - title="Unpublished" - class="ms-1 mt-1 mt-md-0 badge text-bg-danger o_wevent_online_badge_unpublished" - >Non publié</small> - </div> - - <div - class="o_we_agenda_card_content d-flex flex-column justify-content-center my-1" - > - <div class="o_we_agenda_card_title"> - <t t-if="session.website_published or is_event_user"> - <a - t-att-href="'/event/%s/session/%s' % (slug(event), slug(session))" - class="text-black text-bold" - > - <t t-out="session.session_name" /><t - t-if="session.event_session_registrations_sold_out" - > - COMPLET</t> - </a> - </t> - <t t-else=""> - <span class="text-muted text-bold"> - <t t-out="session.session_name" /><t - t-if="session.event_session_registrations_sold_out" - > - COMPLET</t> - </span> - </t> - </div> - - <div class="d-flex justify-content-center flex-wrap"> - <t t-foreach="session.tag_ids" t-as="tag"> - <span - t-if="tag.color" - t-att-title="tag.name" - t-attf-class="me-1 mt-1 badge #{'o_tag_color_'+str(tag.color)}" - t-out="tag.name" - t-attf-onclick=" - var value = '#{tag.name}' ; - var target = $('#event_session_search'); - if (target.val() == value) { target.val(''); } else { target.val(value); } - target.trigger('input'); - " - /> - </t> - </div> - </div> - </div> -</template> - -</odoo> diff --git a/views/event_session_page_templates.xml b/views/event_session_page_templates.xml deleted file mode 100644 index f0d87d5511c30d781ec98a7d0a5af14098b43626..0000000000000000000000000000000000000000 --- a/views/event_session_page_templates.xml +++ /dev/null @@ -1,333 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<odoo> - -<template id="event_session_main" name="Event Exhibitor"> - <t t-call="website_event.layout"> - <div class="o_wevent_online o_wesession_index"> - <!-- Options --> - <t t-set="option_widescreen" t-value="option_widescreen or False" /> - <!-- Drag/Drop Area --> - <div id="oe_structure_wesession_track_index_1" class="oe_structure" /> - <!-- Content --> - <div - t-att-class="'o_wevent_online_page_container %s' % ('container pb-3' if not option_widescreen else 'pb-3')" - > - <div - t-att-class="'row mb-5 mx-0 %s' % ('justify-content-center' if not sessions_other else '')" - > - <t t-if="sessions_other"> - <t t-call="cgscop_website_event.event_session_aside" /> - </t> - <t t-call="cgscop_website_event.event_session_content" /> - </div> - </div> - <!-- Drag/Drop Area --> - <div id="oe_structure_wesession_track_index_2" class="oe_structure" /> - </div> - </t> -</template> - -<!-- ============================================================ --> -<!-- CONTENT: MAIN TEMPLATES --> -<!-- ============================================================ --> - -<template id="event_session_content" name="Session: Main Description"> - <div - name="o_wesession_track_main" - t-att-class="'col-12 o_wesession_track_main o_wevent_theme_bg_base border mt-3 p-0 %s' % ('col-md-9 col-lg-10' if option_widescreen else 'col-md-8 col-lg-9')" - > - <!-- LIVE INFORMATIONS --> - <div - t-if="not session.event_id.is_ongoing and session.event_id.start_remaining" - class="pt-3" - > - <div class="mx-3 alert alert-warning"> - Evènement <span t-out="session.event_id.name" class="fw-bold" /> - <span t-if="session.event_id.start_today"> - commence - <span - t-if="session.event_id.start_remaining >= 1" - t-out="session.event_id.start_remaining" - t-options="{'widget': 'duration', 'digital': False, 'unit': 'minute', 'round': 'minute'}" - /> - <t t-else=""> - dans quelques instants - </t>. - </span> - <span t-else=""> - commence à - <span - t-field="session.event_id.with_context(tz=session.event_id.date_tz).date_begin" - t-options="{'format': 'medium', 'tz_name': session.event_id.date_tz, 'hide_seconds': 'True'}" - /> - (<span t-out="session.event_id.date_tz" />) - </span> - </div> - </div> - <!-- Session DESCRIPTION --> - <div class="o_wesession_track_main_description overflow-auto"> - <div - class="mx-3 pt-3 mb-3 d-flex justify-content-between flex-column flex-md-row" - > - <div class="d-flex flex-column"> - <span class="h4 mb-0" t-out="session.session_name" /><t - t-if="session.event_session_registrations_sold_out" - > - COMPLET</t> - <span t-if="session.seats_max"><t - t-esc="session.seats_available" - /> place(s) restante(s) (<t - t-esc="session.seats_unconfirmed" - /> préinscription(s) en attente).</span> - <div> - <t t-foreach="session.tag_ids" t-as="tag"> - <span - t-if="tag.color" - t-att-class="'badge o_tag_color_hovered_%s' % (tag.color)" - t-out="tag.name" - /> - </t> - </div> - </div> - - </div> - <div class="mx-3"> - <t t-if="session.date_begin"> - <span - t-field="session.date_begin" - t-options='{"hide_seconds":"True", "format": "short", "tz_name": event.date_tz}' - /> - - - <span - t-field="session.date_end" - t-options='{"hide_seconds":"True", "format": "short", "tz_name": event.date_tz}' - /> - <t t-if="event.date_tz"> - (<span t-out="event.date_tz" />) - </t> - </t> - <t t-if="session.duration_slot"> - (<span - t-field="session.duration_slot" - t-options='{"widget": "duration", "unit": "hour", "round": "minute"}' - />) - </t> - </div> - <div class="mx-3 mt-2 text-muted" t-if="session.event_session_slot_ids"> - <ul t-foreach="session.event_session_slot_ids" t-as="slot"> - <li> - <span - t-field="slot.date" - t-options='{"hide_seconds":"True", "format": "short", "tz_name": event.date_tz}' - /> - - - <span - t-field="slot.date_end" - t-options='{"hide_seconds":"True", "format": "short", "tz_name": event.date_tz}' - /> - <t t-if="slot.duration"> - (<span - t-field="slot.duration" - t-options='{"widget": "duration", "unit": "hour", "round": "minute"}' - />) - </t> - </li> - </ul> - </div> - - <hr class="mt-2 mb-0" /> - - <div class="mx-3 mt-2"> - <t t-if="session.intervenant_ids"> - <h4>Intervenants</h4> - <div - t-foreach="session.intervenant_ids" - t-as="intervenant" - class="mt-2 mb-2 d-flex" - > - <div class="ps-2 pe-0 pe-md-2 d-flex flex-grow-1 flex-column"> - <div - t-if="intervenant.partner_name" - t-field="intervenant.partner_name" - class="fw-bold mb-2" - /> - <t - t-call="cgscop_website_event.event_session_content_partner_info" - /> - </div> - </div> - </t> - <hr t-if="not is_html_empty(session.description)" /> - </div> - - <!-- Description --> - <div - t-if="not is_html_empty(session.description)" - t-field="session.description" - class="my-2 mx-3 oe_no_empty" - /> - - <!-- Link--> - <t t-if="session.link"> - <div class="mx-3"> - <hr /> - <div class="my-2 oe_no_empty"> - <a - t-att-href="session.link" - target="_blank" - >Programme de formation</a> - </div> - </div> - </t> - <!-- Link AutoEval--> - <t t-if="session.link_auto_eval"> - <div class="mx-3"> - <hr /> - <div class="my-2 oe_no_empty"> - <a - t-att-href="session.link_auto_eval" - target="_blank" - >Fiche d'Auto Evaluation</a> - </div> - </div> - </t> - </div> - </div> -</template> - - <template id="event_session_content_partner_info"> - <div - class="mb-1 align-items-baseline text-break" - t-if="intervenant.partner_function" - > - <i class="fa fa-briefcase me-2" /><span - t-out="intervenant.partner_function" - /> - <t t-if="intervenant.partner_company_name"> - <span> à </span><span t-out="intervenant.partner_company_name" /> - </t> - </div> - <div - class="mb-1 align-items-baseline text-break" - t-if="intervenant.partner_id.website" - > - <i class="fa fa-home me-2" /><a - t-att-href="intervenant.partner_id.website" - ><span t-field="intervenant.partner_id.website" /></a> - </div> - <div - class="mb-1 align-items-baseline text-break" - t-if="intervenant.partner_email" - > - <i class="fa fa-envelope me-2" /><a - t-att-mailto="intervenant.partner_email" - ><span t-field="intervenant.partner_email" /></a> - </div> - <div - class="mb-1 align-items-baseline text-break" - t-if="intervenant.partner_phone" - > - <i class="fa fa-phone me-2" /><span t-field="intervenant.partner_phone" /> - </div> - <div - class="mb-1 align-items-baseline text-break" - t-if="intervenant.partner_description" - > - <span t-field="intervenant.partner_description" /> - </div> - </template> - -<!-- ============================================================ --> -<!-- ASIDE: CONTROL PANEL --> -<!-- ============================================================ --> - -<template id="event_session_aside" name="Session: Aside"> - <div - t-att-class="'col-12 ps-0 pe-0 mt-3 border o_wevent_online_page_aside o_wesession_track_aside %s' % ('col-md-3 col-lg-2' if option_widescreen else 'col-md-4 col-lg-3')" - > - <div class="o_wevent_theme_bg_base o_wevent_online_page_aside_content"> - <div class="d-flex align-items-center justify-content-between my-2 me-2"> - <ul - class="nav nav-tabs o_wesession_track_aside_nav d-flex border-0" - role="tablist" - > - <li class="nav-item flex-grow-1"> - <a - href="#session_list" - aria-controls="session_list" - class="nav-link active" - role="tab" - data-bs-toggle="tab" - > - Ateliers - </a> - </li> - </ul> - <a - href="#collapse_session_aside" - data-bs-toggle="collapse" - class="d-md-none p-2 text-decoration-none o_wevent_online_page_aside_collapse collapsed" - > - <i class="fa fa-chevron-down d-md-none" /> - </a> - </div> - <div - id="collapse_session_aside" - class="tab-content collapse d-md-block o_wesession_track_aside_tabs" - > - <div - class="tab-pane fade show active" - id="session_list" - role="tabpanel" - > - <ul class="list-unstyled mb-0"> - <li - t-foreach="sessions_other" - t-as="session_other" - class="w-100" - > - <a - t-if="is_event_user or session_other.is_published" - t-att-data-publish="session_other.website_published and 'on' or 'off'" - class="d-block w-100 h-100 px-2 pt-2 pb-1 text-decoration-none" - t-att-href="session_other.website_url" - > - <t - t-call="cgscop_website_event.event_session_aside_other_session" - /> - </a> - <div t-else="" class="text-muted px-2 pt-2 pb-1"> - <div - t-att-data-publish="session_other.website_published and 'on' or 'off'" - > - <t - t-call="cgscop_website_event.event_session_aside_other_session" - /> - </div> - </div> - </li> - </ul> - </div> - </div> - </div> - </div> -</template> - -<template id="event_session_aside_other_session"> - <span t-out="session_other.session_name" class="w-100" /> - <div class="d-flex align-items-center"> - <div class="d-inline-block ms-auto o_wesession_track_aside_info text-truncate"> - <small - t-if="not session_other.website_published and user_event_manager" - class="badge text-bg-danger" - >Non publiée</small> - <div t-elif="session_other.date_begin" class="badge text-bg-light"> - <span - t-out="session_other.date_begin" - t-options="{'widget': 'datetime', 'tz_name': session_other.event_id.date_tz, 'format': 'MMM. dd'}" - /> - </div> - </div> - </div> -</template> - -</odoo> diff --git a/views/event_session_template_list.xml b/views/event_session_template_list.xml deleted file mode 100644 index 23a56eb2604df4aa66187c62be2f8444279cb701..0000000000000000000000000000000000000000 --- a/views/event_session_template_list.xml +++ /dev/null @@ -1,327 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<odoo> - -<template id="sessions_session" name="Event Sessions"> - <t t-call="website_event.layout"> - <div class="o_wevent_online o_wesession_index"> - <!-- Topbar --> - <t t-call="cgscop_website_event.session_topbar" /> - <!-- Drag/Drop Area --> - <div id="oe_structure_wesession_index_1" class="oe_structure" /> - <!-- Content --> - <div class="o_wesession_container container"> - <div class="row"> - <t t-call="cgscop_website_event.sessions_search" /> - </div> - <div class="row"> - <t t-call="cgscop_website_event.sessions_main" /> - </div> - </div> - <!-- Drag/Drop Area --> - <div id="oe_structure_wesession_index_2" class="oe_structure mb-5" /> - </div> - </t> -</template> - -<!-- ============================================================ --> -<!-- TOPBAR: BASE NAVIGATION --> -<!-- ============================================================ --> - -<!-- Main topbar --> -<template id="session_topbar" name="Sessions Tools"> - <nav class="navbar navbar-light border-top shadow-sm d-print-none"> - <div class="container"> - <ul class="o_wesession_topbar_filters o_wevent_index_topbar_filters nav"> - </ul> - <div class="d-flex flex-column flex-sm-row justify-content-between w-100"> - <div class="d-flex align-items-center flex-wrap ps-sm-3 pe-0"> - <t t-call="website_event.events_search_box"> - <t t-set="_searches" t-value="searches" /> - <t - t-set="action" - t-value="'/event/%s/session' % (slug(event))" - /> - <t t-set="_placeholder" t-value="'Rechercher un atelier ...'" /> - </t> - </div> - </div> - </div> - </nav> -</template> - -<!-- Option: Topbar: optional tags filters--> -<template - id="session_topbar_tag" - inherit_id="cgscop_website_event.session_topbar" - name="Filter by Tags" - active="True" - > - <xpath expr="//ul[hasclass('o_wesession_topbar_filters')]" position="inside"> - <t t-foreach="tag_categories" t-as="tag_category"> - <li - t-if="tag_category.tag_ids and any(tag.color for tag in tag_category.tag_ids)" - class="nav-item dropdown me-2 my-1" - > - <a - href="#" - role="button" - class="btn dropdown-toggle" - data-bs-toggle="dropdown" - > - <i class="fa fa-folder-open" /> - <t t-out="tag_category.name" /> - </a> - <div class="dropdown-menu"> - <t t-foreach="tag_category.tag_ids" t-as="tag"> - <a - t-att-href="'/event/%s/session?%s' % ( - slug(event), - keep_query('*', tags=str((search_tags - tag).ids if tag in search_tags else (tag | search_tags).ids)) - )" - t-if="tag.color" - t-attf-class="dropdown-item d-flex align-items-center justify-content-between #{'active' if tag in search_tags else ''}" - > - <t t-out="tag.name" /> - </a> - </t> - </div> - </li> - </t> - </xpath> -</template> - -<!-- ============================================================ --> -<!-- CONTENT: MAIN TEMPLATES --> -<!-- ============================================================ --> - -<!-- Sessions Main Display --> -<template id="sessions_main" name="Sessions: Main Display"> - <!-- No sessions --> - <t t-if="not sessions"> - <div class="col-12"> - <div class="h2 mb-3">Pas d'ateliers trouvés.</div> - <div t-if="search_key" class="alert alert-info text-center"> - <p class="m-0">Il n'y a pas d'ateiliers correpondants à votre <strong - t-out="search_key" - /> recherche.</p> - </div> - </div> - </t> - <div class="col-12" t-call="cgscop_website_event.sessions_display_list" /> -</template> - -<!-- Sessions: List-based display --> -<template id="sessions_display_list" name="Sessions: List Display"> - <div t-if="sessions"> - <h1>Liste des ateliers</h1> - </div> - <div t-if="sessions" class="o_wesession_list mb-3"> - <ul class="list-unstyled"> - <li t-foreach="sessions_by_day" t-as="sessions_info" class="mb-5"> - <t t-set="sessions_date" t-value="sessions_info['date_begin']" /> - <t t-set="sessions_header_name" t-value="sessions_info['name']" /> - <t t-set="sessions" t-value="sessions_info['sessions']" /> - <!-- DAY HEADER --> - <div class="o_we_session_day_header d-flex"> - <div class="d-flex flex-grow-1" t-if="sessions_date"> - <span - class="h1 m-0 fw-bold" - t-out="sessions_date" - t-options="{'widget': 'date', 'format': 'EEEE dd'}" - /> - <div class="d-flex ms-3 me-2 flex-column"> - <span - class="fw-bold" - t-out="sessions_date" - t-options="{'widget': 'date', 'format': 'MMMM'}" - /> - <span - class="fw-bold" - t-out="sessions_date" - t-options="{'widget': 'date', 'format': 'YYYY'}" - /> - </div> - <div - class="flex-column align-self-center ms-2 d-none d-sm-block" - > - <span class="small fw-light">(<t - t-out="event.date_tz" - />)</span> - </div> - </div> - <div class="d-flex flex-grow-1" t-elif="sessions_header_name"> - <span class="h1 m-0 fw-bold" t-out="sessions_header_name" /> - </div> - <a - t-attf-class="ms-auto align-self-start text-black {{ 'collapsed' if not sessions_info['default_collapsed'] else '' }}" - t-attf-href="#collapse_session_list_{{ sessions_info_index }}" - t-attf-aria-controls="collapse_session_list_{{ sessions_info_index }}" - t-att-aria-expanded="'false' if not sessions_info['default_collapsed'] else 'true'" - data-bs-toggle="collapse" - > - <i class="fa fa-2x fa-chevron-down" /> - </a> - <hr class="mt-2 mb-2" /> - </div> - <!-- DAY Sessions LIST --> - <div - t-attf-class="collapse {{ '' if not sessions_info['default_collapsed'] else 'show' }}" - t-attf-id="collapse_session_list_{{ sessions_info_index }}" - > - <div - t-foreach="sessions" - t-as="session" - t-att-class="'o_wesession_list_item px-2 py-2 event_color_%d' % (session.color)" - > - <div class="row g-0"> - <!-- Main column: name, speaker --> - <div class="col-md-7"> - <span class="h5 mb0"> - <a - t-if="session.website_published or is_event_user" - class="me-2" - t-att-href="session.website_url" - > - <span t-field="session.session_name" /><t - t-if="session.event_session_registrations_sold_out" - > - COMPLET</t> - </a> - <t t-else=""> - <span - class="me-2" - t-field="session.session_name" - /><t - t-if="session.event_session_registrations_sold_out" - > - COMPLET</t> - </t> - <span - t-if="not session.website_published and is_event_user" - class="badge text-bg-danger o_wevent_online_badge_unpublished" - > - Non publié - </span> - </span> - <div class="d-flex align-items-center"> - <span t-if="session.seats_max"><t - t-esc="session.seats_available" - /> place(s) restante(s) (<t - t-esc="session.seats_unconfirmed" - /> préinscription(s) en attente).<br - /></span> - </div> - <div class="d-flex flex-column"> - <t - t-if="sessions_date and today_tz <= sessions_date" - > - <span>Durée: - <t - class="d-none d-md-block " - t-esc="session.duration_slot" - t-options="{'widget': 'duration', 'digital': False, 'format': 'short', 'unit': 'hour', 'round': 'minute'}" - /></span> - </t> - </div> - <div class="text-muted d-flex flex-column"> - <ul - t-foreach="session.event_session_slot_ids" - t-as="slot" - > - <li> - <span - t-field="slot.date" - t-options='{"hide_seconds":"True", "format": "short", "tz_name": event.date_tz}' - /> - - - <span - t-field="slot.date_end" - t-options='{"hide_seconds":"True", "format": "short", "tz_name": event.date_tz}' - /> - <t t-if="slot.duration"> - (<span - t-field="slot.duration" - t-options='{"widget": "duration", "unit": "hour", "round": "minute"}' - />) - </t> - </li> - </ul> - </div> - </div> - <!-- Aside column: date, tags --> - <div class="col-md-5 align-self-center"> - <!-- Tags: desktop only --> - <div class="d-none d-md-block"> - <t t-foreach="session.tag_ids" t-as="tag"> - <t - t-if="tag.color" - t-call="cgscop_website_event.session_tag_badge_link" - /> - </t> - </div> - </div> - </div> - </div> - </div> - </li> - </ul> - </div> -</template> - -<!-- Searched tags --> -<template id="sessions_search" name="sessions: search tags"> - <div class="d-flex align-items-center mb-3"> - <t t-foreach="search_tags" t-as="tag"> - <span - class="align-items-baseline border d-inline-flex ps-2 mt-3 rounded ml16 mb-2 bg-white" - > - <i class="fa fa-tag me-2 text-muted" /> - <t t-out="tag.display_name" /> - <a - t-att-href="'/event/%s/session?%s' % (slug(event), keep_query('*', tags=str((search_tags - tag).ids)))" - class="btn border-0 py-1" - > - × - </a> - </span> - </t> - </div> -</template> - -<!-- ============================================================ --> -<!-- MISC TOOLS --> -<!-- ============================================================ --> - -<template id="session_tag_badge_link" name="session: Tag Badge Link"> - <a - t-if="search_tags" - t-att-href="'/event/%s/session?%s'% ( - slug(event), - keep_query('*', tags=str((search_tags - tag).ids if tag in search_tags else (tag | search_tags).ids)) - )" - t-att-class="'badge %s' % ('text-bg-primary' if tag in search_tags else 'o_tag_color_hovered_0')" - t-out="tag.name" - /> - <a - t-else="" - t-att-href="'/event/%s/session?%s'% ( - slug(event), - keep_query('*', tags=str(tag.ids)) - )" - t-att-class="'badge o_tag_color_hovered_%s' % (tag.color)" - t-out="tag.name" - /> -</template> - -<template id="session_tag_badge_info" name="session: Tag Badge Info"> - <span - t-if="search_tags" - t-att-class="'badge %s' % ('text-bg-primary' if tag in search_tags else 'o_tag_color_0')" - t-out="tag.name" - /> - <span - t-else="" - t-att-class="'badge o_tag_color_%s' % (tag.color)" - t-out="tag.name" - /> -</template> - -</odoo> diff --git a/views/event_session_views.xml b/views/event_session_views.xml deleted file mode 100644 index e8762cad76692d9c786f41f9943a39f6d6e300fb..0000000000000000000000000000000000000000 --- a/views/event_session_views.xml +++ /dev/null @@ -1,189 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<odoo> - - <record id="view_event_session_form" model="ir.ui.view"> - <field name="model">event.session</field> - <field name="name">event.session.form.inherit</field> - <field name="inherit_id" ref="event_session.view_event_session_form" /> - <field name="arch" type="xml"> - <button name="action_open_registrations" position="after"> - <field name="website_url" invisible="1" /> - <field name="is_published" widget="website_redirect_button" /> - </button> - - <field name="name" position="attributes"> - <attribute name="invisible">1</attribute> - </field> - - <field name="session_update" position="attributes"> - <attribute name="options">{'horizontal': true}</attribute> - </field> - <!-- Title --> - <div class="oe_title" position="inside"> - <h2> - <field - class="o_text_overflow" - name="session_name" - placeholder="Titre de l'atelier" - required="1" - /> - </h2> - </div> - - <label for="date_begin" position="attributes"> - <attribute name="invisible">1</attribute> - </label> - <div class="o_row" position="replace"> - <field name="date_begin" invisible="1" /> - <field invisible="1" name="date_end" /> - </div> - - <!-- Slots --> - <field name="date_tz" position="before"> - <label for="event_session_slot_ids" /> - <div class="o_row" colspan="2"> - <field name="event_session_slot_ids" required="1"> - <tree> - <field name="date" /> - <field name="duration" /> - <field name="date_end" /> - </tree> - <form> - <sheet> - <group name="left"> - <label for="date" string="Date" /> - <div class="o_row"> - <field - name="date" - widget="daterange" - nolabel="1" - class="oe_inline" - options="{'related_end_date': 'date_end'}" - required="1" - /> - <i - class="fa fa-long-arrow-right mx-2" - aria-label="Arrow icon" - title="Arrow" - /> - <field - name="date_end" - widget="daterange" - nolabel="1" - class="oe_inline" - options="{'related_start_date': 'date'}" - /> - </div> - <field name="duration" /> - </group> - </sheet> - </form> - </field> - </div> - <field name="duration_slot" /> - <field name="duration" invisible="1" /> - </field> - - <!-- Seats --> - <group name="right" position="inside"> - <field name="seats_max" /> - <field name="seats_min" /> - <field name="seats_available" string="Places disponibles" /> - <field name="seats_available_unconfirmed" /> - <field name="color" widget="color_picker" /> - <field - name="tag_ids" - widget="many2many_tags" - options="{'color_field': 'color', 'no_quick_create': True}" - /> - </group> - - <!-- Notebook --> - <xpath expr="//notebook" position="before"> - <group> - <field name="description" /> - <field name="link" widget="url" /> - <field name="link_auto_eval" widget="url" /> - </group> - </xpath> - <xpath expr="//notebook" position="inside"> - <page string="Intervenants" name="speakers"> - <field - name="intervenant_ids" - mode="tree" - context="{'default_session_id': active_id}" - > - <tree string="Intervenants" editable="bottom"> - <field - name="partner_id" - context="{'default_phone': partner_phone, 'default_email': partner_email}" - /> - - <field name="partner_name" /> - <field name="partner_email" /> - <field name="partner_phone" class="o_force_ltr" /> - <field name="partner_description" /> - </tree> - </field> - </page> - </xpath> - </field> - </record> - - <record model="ir.ui.view" id="view_event_session_kanban"> - <field name="model">event.session</field> - <field name="inherit_id" ref="event_session.view_event_session_kanban" /> - <field name="arch" type="xml"> - <xpath expr="//kanban/field[@name='name']" position="after"> - <field name="session_name" /> - </xpath> - <xpath expr="//templates//field[@name='name']" position="after"> - <br /><strong><field name="session_name" /></strong> - </xpath> - <xpath expr="//templates//field[@name='name']" position="attributes"> - <atttibute name="invisible">1</atttibute> - </xpath> - </field> - </record> - - <record id="view_event_session_tree" model="ir.ui.view"> - <field name="model">event.session</field> - <field name="inherit_id" ref="event_session.view_event_session_tree" /> - <field name="arch" type="xml"> - <field name="event_id" position="after"> - <field name="session_name" /> - </field> - </field> - </record> - - <record id="view_event_registration_form" model="ir.ui.view"> - <field name="model">event.registration</field> - <field name="inherit_id" ref="event_session.view_event_registration_form" /> - <field name="arch" type="xml"> - <xpath expr="//field[@name='session_id']" position="attributes"> - <atttibute name="required">0</atttibute> - <atttibute name="attrs">{}</atttibute> - </xpath> - <xpath expr="//field[@name='name']" position="after"> - <field name="partner_lastname" /> - <field name="partner_firstname" /> - </xpath> - </field> - </record> - - <record id="event_registration_view_kanban" model="ir.ui.view"> - <field name="model">event.registration</field> - <field name="inherit_id" ref="event_session.event_registration_view_kanban" /> - <field name="arch" type="xml"> - <xpath expr="//field[@name='session_id']" position="attributes"> - <atttibute name="required">0</atttibute> - <atttibute name="attrs">{}</atttibute> - </xpath> - </field> - </record> - - <record id="event_session.event_session_menu" model="ir.ui.menu"> - <field name="active" eval="False" /> - </record> - -</odoo> diff --git a/views/event_tag_views.xml b/views/event_tag_views.xml deleted file mode 100644 index 4e90e4e6ecd16274fa2d0eb48deca72034f3c3b3..0000000000000000000000000000000000000000 --- a/views/event_tag_views.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" ?> -<odoo> - - <record id="event_tag_category_view_form" model="ir.ui.view"> - <field name="name">event.tag.category.view.form.inherit</field> - <field name="model">event.tag.category</field> - <field name="inherit_id" ref="event.event_tag_category_view_form" /> - <field name="arch" type="xml"> - <xpath expr="//group" position="inside"> - <field name="company_id" /> - </xpath> - </field> - </record> - - <record id="event_tag_view_form" model="ir.ui.view"> - <field name="name">event.tag.view.form.inherit</field> - <field name="inherit_id" ref="event.event_tag_view_form" /> - <field name="model">event.tag</field> - <field name="arch" type="xml"> - <xpath expr="//group" position="inside"> - <field name="company_id" /> - </xpath> - </field> - </record> - -</odoo> diff --git a/views/event_template.xml b/views/event_template.xml deleted file mode 100644 index 43704d29f4146aa009ca3e1b6566ffff4c48bb31..0000000000000000000000000000000000000000 --- a/views/event_template.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<odoo> - - <template - id="layout" - inherit_id="website_event.layout" - name="Event website layout" - priority="20" - > - <xpath expr="//a[@t-field='event.name']" position="attributes"> - <attribute name="t-if">not event.hide_website_event_title</attribute> - </xpath> - </template> - -</odoo> diff --git a/views/event_template_page_registration.xml b/views/event_template_page_registration.xml deleted file mode 100644 index 45dc3bf90f69c4d2276bfe0488758757ac7fbbee..0000000000000000000000000000000000000000 --- a/views/event_template_page_registration.xml +++ /dev/null @@ -1,248 +0,0 @@ -<?xml version="1.0" encoding="utf-8" ?> -<odoo> - - <template - id="registration_attendee_details_sessions" - inherit_id="website_event.registration_attendee_details" - name="Registration Attendee Details with sessions" - priority="20" - > - <div class="row" position="replace"> - <div class="row"> - <div class="col-lg my-2"> - <label>Nom *</label> - <input - class="form-control" - type="text" - t-attf-name="#{counter}-partner_lastname" - required="Ce champ ets obligatoire" - t-att-value="default_first_attendee.get('partner_lastname', '') if counter == 1 else ''" - /> - </div><div class="col-lg my-2"> - <label>Prénom *</label> - <input - class="form-control" - type="text" - t-attf-name="#{counter}-partner_firstname" - required="Ce champ ets obligatoire" - t-att-value="default_first_attendee.get('partner_firstname', '') if counter == 1 else ''" - /> - </div> - <div class="col-lg my-2"> - <label>Mail *</label> - <input - class="form-control" - type="email" - t-attf-name="#{counter}-email" - required="Ce champ ets obligatoire" - t-att-value="default_first_attendee.get('email', '') if counter == 1 else ''" - /> - </div> - <div class="col-lg my-2"> - <label>Téléphone <small>(Optionel)</small></label> - <input - class="form-control" - type="tel" - t-attf-name="#{counter}-phone" - t-att-value="default_first_attendee.get('phone', '') if counter == 1 else ''" - /> - </div> - <input - class="d-none" - type="text" - t-attf-name="#{counter}-event_ticket_id" - t-attf-value="#{ticket['id']}" - /> - </div> - </div> - <!-- Sessions --> - <xpath - expr="//t[@name='attendee_loop']//*[hasclass('modal-body')]" - position="inside" - > - <div - t-if="event.use_sessions" - class="o_wevent_event o_wesession_list mb-3 mt-5 " - > - <h3>Sélectionner les ateliers auxquels vous voulez participer</h3> - <ul class="list-unstyled"> - <li t-foreach="sessions_by_day" t-as="sessions_info" class="mb-5"> - <t - t-set="sessions_date" - t-value="sessions_info['date_begin']" - /> - <t - t-set="sessions_header_name" - t-value="sessions_info['name']" - /> - <t t-set="sessions" t-value="sessions_info['sessions']" /> - <t t-call="cgscop_website_event.registration_event_session"> - <t t-set="registration_index" t-value="counter" /> - </t> - </li> - </ul> - </div> - </xpath> - - </template> - - <template id="registration_event_session" name="Registration Event Session"> - <!-- DAY HEADER --> - <div class="o_we_session_day_header d-flex"> - <div class="d-flex flex-grow-1" t-if="sessions_date"> - <span - class="h2 m-0 fw-bold" - t-out="sessions_date" - t-options="{'widget': 'date', 'format': 'EEEE dd'}" - /> - <div class="d-flex ms-3 me-2 flex-column"> - <span - class="fw-bold" - t-out="sessions_date" - t-options="{'widget': 'date', 'format': 'MMMM'}" - /> - <span - class="fw-bold" - t-out="sessions_date" - t-options="{'widget': 'date', 'format': 'YYYY'}" - /> - </div> - <div class="flex-column align-self-center ms-2 d-none d-sm-block"> - <span class="small fw-light">(<t t-out="event.date_tz" />)</span> - </div> - </div> - <div class="d-flex flex-grow-1" t-elif="sessions_header_name"> - <span class="h2 m-0 fw-bold" t-out="sessions_header_name" /> - </div> - <a - t-attf-class="ms-auto align-self-start text-black {{ 'collapsed' if not sessions_info['default_collapsed'] else '' }}" - t-attf-href="#collapse_session_list_{{ sessions_info_index }}" - t-attf-aria-controls="collapse_session_list_{{ sessions_info_index }}" - t-att-aria-expanded="'false' if not sessions_info['default_collapsed'] else 'true'" - data-bs-toggle="collapse" - > - <i class="fa fa-2x fa-chevron-down" /> - </a> - <hr class="mt-2 mb-2" /> - </div> - <!-- DAY Sessions LIST --> - <div - t-attf-class="collapse {{ '' if not sessions_info['default_collapsed'] else 'show' }}" - t-attf-id="collapse_session_list_{{ sessions_info_index }}" - > - <div - t-foreach="sessions" - t-as="session" - t-att-class="'o_wesession_list_item px-2 py-2 event_color_%d' % (session.color)" - > - <div class="row g-0"> - <!-- Main column: name, speaker --> - <div class="col-md-7"> - <span class="h5 mb0"> - <t t-if="not session.event_session_registrations_sold_out"> - <input - t-att-value="session.id" - type="checkbox" - t-att-id="session.id" - t-attf-name="session_id-#{session.id}" - /> - </t> - <span t-field="session.session_name" /> - <t t-if="session.event_session_registrations_sold_out"> - - COMPLET - </t> - <span - t-if="not session.website_published and is_event_user" - class="badge text-bg-danger o_wevent_online_badge_unpublished" - > - Non Publié - </span> - </span> - <div class="text-muted d-flex flex-column"> - <t t-if="session.seats_max"> - <span t-if="session.seats_max"><t - t-esc="session.seats_available" - /> place(s) restante(s) (<t - t-esc="session.seats_unconfirmed" - /> préinscription(s) en attente).</span> - </t> - <span>Durée: - <t - class="d-none d-md-block " - t-esc="session.duration_slot" - t-options="{'widget': 'duration', 'digital': False, 'format': 'short', 'unit': 'hour', 'round': 'minute'}" - /> - </span> - </div> - <div class="text-muted d-flex flex-column"> - <ul t-foreach="session.event_session_slot_ids" t-as="slot"> - <li> - <span - t-field="slot.date" - t-options='{"hide_seconds":"True", "format": "short", "tz_name": event.date_tz}' - /> - - - <span - t-field="slot.date_end" - t-options='{"hide_seconds":"True", "format": "short", "tz_name": event.date_tz}' - /> - <t t-if="slot.duration"> - (<span - t-field="slot.duration" - t-options='{"widget": "duration", "unit": "hour", "round": "minute"}' - />) - </t> - </li> - </ul> - </div> - </div> - <!-- Aside column: date, tags --> - <div class="col-md-5 align-self-center"> - <!-- Tags: desktop only --> - <div class="d-none d-md-block"> - <t t-foreach="session.tag_ids" t-as="tag"> - <t - t-if="tag.color" - t-call="cgscop_website_event.session_tag_badge_link" - /> - </t> - </div> - </div> - </div> - </div> - </div> - </template> - - - <template - id="registration_complete" - inherit_id="website_event.registration_complete" - name="Registration Complete with sessions" - priority="20" - > - <xpath expr="//div[hasclass('flex-column')]" position="attributes"> - <attribute name="t-if">not attendee.session_id</attribute> - </xpath> - <xpath expr="//div[hasclass('flex-column')]" position="after"> - <div class="d-flex flex-column" t-if="attendee.session_id"> - <span class="text-truncate"> - <u>Atelier :</u> - </span> - <span class="fw-bold text-truncate"> - <t - t-if="attendee.session_id.session_name" - t-out="attendee.session_id.session_name" - /> - <t t-else="">N/A</t> - </span> - <span class="text-truncate text-muted"> - Début : <span t-field="attendee.session_id.date_begin" /> - </span> - <span class="text-truncate text-muted"> - Fin : <span t-field="attendee.session_id.date_end" /> - </span> - </div> - </xpath> - </template> - -</odoo> diff --git a/views/event_views.xml b/views/event_views.xml index da2fbdf12a6e4030c837bab0c9b00bf80f53bacf..2c1993c00b98c39eb14feded8cb42fd0833f4941 100644 --- a/views/event_views.xml +++ b/views/event_views.xml @@ -1,98 +1,16 @@ -<?xml version="1.0" encoding="utf-8" ?> +<?xml version="1.0" encoding="utf-8"?> <odoo> - <record id="view_event_form_create_sessions" model="ir.ui.view"> - <field name="model">event.event</field> - <field name="name">event.event.form.inherit.button</field> - <field name="inherit_id" ref="event_session.view_event_form_create_sessions" /> - <field name="arch" type="xml"> - <button - name="%(event_session.act_wizard_event_session)d" - position="attributes" - > - <attribute name="attrs">{}</attribute> - <attribute name="invisible">1</attribute> - </button> - </field> - </record> - <record id="event_event_view_form" model="ir.ui.view"> - <field name="name">event.event.view.from.inherit.sesson</field> - <field name="inherit_id" ref="website_event.event_event_view_form" /> + <field name="name">scop.event.event.view.from.inherit</field> + <field name="inherit_id" ref="website_event.event_event_view_form"/> <field name="model">event.event</field> + <field name="priority" eval="10"/> <field name="arch" type="xml"> - <xpath expr="//field[@name='website_menu']" position="after"> - <label - for="website_session" - attrs="{'invisible': [('use_sessions', '=', False)]}" - groups="cgscop_website_event.group_event_session" - /> - <field - name="website_session" - attrs="{'invisible': [('use_sessions', '=', False)]}" - groups="cgscop_website_event.group_event_session" - /> + <xpath expr="//field[@name='location_menu']" position="after"> + <field name="hosting_menu" invisible="1"/> + <field name="program_menu" invisible="1"/> </xpath> - <field name="event_type_id" position="before"> - <field name="type_event_cg" /> - <field name="hide_website_event_title" /> - </field> </field> </record> - - <record model="ir.ui.view" id="view_event_type_form"> - <field name="name">event.type.form.inherit.type</field> - <field name="model">event.type</field> - <field name="inherit_id" ref="event.view_event_type_form" /> - <field name="arch" type="xml"> - <field name="default_timezone" position="before"> - <field name="type_event_cg" /> - </field> - </field> - </record> - - <record id="view_restrict_event_session_form" model="ir.ui.view"> - <field name="model">event.event</field> - <field name="name">event session restrict</field> - <field name="inherit_id" ref="event_session.view_event_form_create_sessions" /> - <field name="priority">50</field> - <field name="arch" type="xml"> - <xpath expr="//header" position="inside"> - <button - name="active_sessions" - type="object" - string="Activer les séances" - class="btn-outline-primary" - attrs="{'invisible': [('use_sessions', '=', True)]}" - groups="cgscop_website_event.group_event_session" - /> - <button - name="active_sessions" - type="object" - string="Désactiver les séances" - class="btn-outline-primary" - attrs="{'invisible': [('use_sessions', '!=', True)]}" - groups="cgscop_website_event.group_event_session" - confirm="La désactivation des séances va entrainer la suppression des séances de cet évènement." - /> - <button - name="action_dup_event_and_web" - type="object" - string="Dupliquer avec site web" - class="btn-outline-primary" - /> - </xpath> - <xpath expr="//field[@name='use_sessions']" position="attributes"> - <attribute name="invisible">True</attribute> - </xpath> - </field> - </record> - - <record model="ir.ui.menu" id="event_session.event_session_menu_report"> - <field - name="groups_id" - eval="[(6,0,[ref('cgscop_website_event.group_event_session')])]" - /> - </record> - </odoo>