diff options
| -rw-r--r-- | addons/website_event/controllers/main.py | 78 | ||||
| -rw-r--r-- | addons/website_event/static/src/scss/website_event.scss | 6 | ||||
| -rw-r--r-- | addons/website_event/views/event_templates.xml | 160 | ||||
| -rw-r--r-- | addons/website_event_questions/controllers/main.py | 4 | ||||
| -rw-r--r-- | addons/website_event_sale/controllers/main.py | 70 | ||||
| -rw-r--r-- | addons/website_event_sale/views/website_event_templates.xml | 141 |
6 files changed, 239 insertions, 220 deletions
diff --git a/addons/website_event/controllers/main.py b/addons/website_event/controllers/main.py index d4d8e7f06ca..dfb66f7f834 100644 --- a/addons/website_event/controllers/main.py +++ b/addons/website_event/controllers/main.py @@ -254,25 +254,62 @@ class WebsiteEventController(http.Controller): "url": event.website_url}) return request.env['ir.ui.view'].render_template("website_event.country_events_list", result) - def _process_tickets_details(self, data): - nb_register = int(data.get('nb_register-0', 0)) - if nb_register: - return [{'id': 0, 'name': 'Registration', 'quantity': nb_register, 'price': 0}] - return [] + def _process_tickets_form(self, event, form_details): + """ Process posted data about ticket order. Generic ticket are supported + for event without tickets (generic registration). + + :return: list of order per ticket: [{ + 'id': if of ticket if any (0 if no ticket), + 'ticket': browse record of ticket if any (None if no ticket), + 'name': ticket name (or generic 'Registration' name if no ticket), + 'quantity': number of registrations for that ticket, + }, {...}] + """ + ticket_order = {} + for key, value in form_details.items(): + registration_items = key.split('nb_register-') + if len(registration_items) != 2: + continue + ticket_order[int(registration_items[1])] = int(value) + + ticket_dict = dict((ticket.id, ticket) for ticket in request.env['event.event.ticket'].search([ + ('id', 'in', [tid for tid in ticket_order.keys() if tid]), + ('event_id', '=', event.id) + ])) + + return [{ + 'id': tid if ticket_dict.get(tid) else 0, + 'ticket': ticket_dict.get(tid), + 'name': ticket_dict[tid]['name'] if ticket_dict.get(tid) else _('Registration'), + 'quantity': count, + } for tid, count in ticket_order.items() if count] @http.route(['/event/<model("event.event"):event>/registration/new'], type='json', auth="public", methods=['POST'], website=True) def registration_new(self, event, **post): - tickets = self._process_tickets_details(post) + tickets = self._process_tickets_form(event, post) if not tickets: return False return request.env['ir.ui.view'].render_template("website_event.registration_attendee_details", {'tickets': tickets, 'event': event}) - def _process_registration_details(self, details): - ''' Process data posted from the attendee details form. ''' + def _process_attendees_form(self, event, form_details): + """ Process data posted from the attendee details form. + + :param details: posted data from frontend registration form, like + {'1-name': 'r', '1-email': 'r@r.com', '1-phone': '', '1-event_ticket_id': '1'} + """ + registration_fields = request.env['event.registration']._fields + registrations = {} global_values = {} - for key, value in details.items(): + for key, value in form_details.items(): counter, field_name = key.split('-', 1) + if field_name not in registration_fields: + continue + elif isinstance(registration_fields[field_name], (fields.Many2one, fields.Integer)): + value = int(value) + else: + value = value + if counter == '0': global_values[field_name] = value else: @@ -282,23 +319,28 @@ class WebsiteEventController(http.Controller): registration[key] = value return list(registrations.values()) + def _create_attendees_from_registration_post(self, event, registration_data): + attendees_sudo = request.env['event.registration'].sudo() + + for registration_values in registration_data: + registration_values['event_id'] = event.id + if not registration_values.get('partner_id'): + registration_values['partner_id'] = request.env.user.partner_id.id + attendees_sudo += request.env['event.registration'].sudo().create(registration_values) + + return attendees_sudo + @http.route(['''/event/<model("event.event"):event>/registration/confirm'''], type='http', auth="public", methods=['POST'], website=True) def registration_confirm(self, event, **post): if not event.can_access_from_current_website(): raise werkzeug.exceptions.NotFound() - Attendees = request.env['event.registration'] - registrations = self._process_registration_details(post) - - for registration_vals in registrations: - registration_vals['event_id'] = event.id - if not registration_vals.get('partner_id'): - registration_vals['partner_id'] = request.env.user.partner_id.id - Attendees += Attendees.sudo().create(registration_vals) + registrations = self._process_attendees_form(event, post) + attendees = self._create_attendees_from_registration_post(event, registrations) urls = event._get_event_resource_urls() return request.render("website_event.registration_complete", { - 'attendees': Attendees.sudo(), + 'attendees': attendees, 'event': event, 'google_url': urls.get('google_url'), 'iCal_url': urls.get('iCal_url') diff --git a/addons/website_event/static/src/scss/website_event.scss b/addons/website_event/static/src/scss/website_event.scss index 576d0360bb6..ebd7d31ce2b 100644 --- a/addons/website_event/static/src/scss/website_event.scss +++ b/addons/website_event/static/src/scss/website_event.scss @@ -269,3 +269,9 @@ $o-wevent-event-title-sizes-variants: ( } } } + +.modal-open { + > .modal-backdrop { + z-index: $zindex-dropdown - 1; + } +} diff --git a/addons/website_event/views/event_templates.xml b/addons/website_event/views/event_templates.xml index bc08e29530c..52a9e9be649 100644 --- a/addons/website_event/views/event_templates.xml +++ b/addons/website_event/views/event_templates.xml @@ -209,7 +209,18 @@ </main> <!-- Footer --> <footer t-attf-class="small #{opt_events_list_cards and 'card-footer' or ((not opt_events_list_columns) and 'border-top mx-4 mt-auto pt-2' or 'border-top py-2')}"> - <div itemprop="price"><span content="0" class="font-weight-bold text-uppercase">Free</span></div> + <t t-if="event.event_registrations_open"> + <span class="text-danger" + t-if="event.seats_availability == 'limited' and not event.seats_available"> + Sold Out + </span> + <span class="text-muted" + t-if="event.seats_availability == 'limited' and + event.seats_available and + (event.seats_available <5 or event.seats_available <= ((event.seats_max or 0) / 4))"> + <em>Only <t t-esc="event.seats_available"/> Remaining</em> + </span> + </t> </footer> </div> </div> @@ -505,22 +516,109 @@ <!-- Event - Registration --> <template id="registration_template"> - <form t-if="event.event_registrations_open" id="registration_form" t-attf-action="/event/#{slug(event)}/registration/new" method="post" itemscope="itemscope" itemprop="offers" itemtype="http://schema.org/AggregateOffer" class="mb-5"> + <div t-if="event.start_sale_date and event.start_sale_date > datetime.date.today() and not event.event_registrations_open" + class="alert alert-info mb-5" role="status"> + <em >Ticket Sales starting on <t t-esc="event.start_sale_date"/></em> + </div> + <form t-if="event.event_registrations_open and (not event.event_ticket_ids or not all([ticket.is_expired for ticket in event.event_ticket_ids]))" + id="registration_form" + t-attf-action="/event/#{slug(event)}/registration/new" method="post" + class="mb-5" itemscope="itemscope" itemprop="offers" itemtype="http://schema.org/AggregateOffer"> <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/> <div id="o_wevent_tickets" class="bg-white rounded shadow-sm"> - <t t-set="quantity"> - <select name="nb_register-0" class="custom-select w-auto"> - <t t-foreach="range(0, (event.seats_availability == 'unlimited' or event.seats_available > 9) and 10 or event.seats_available+1)" t-as="nb"> - <option t-esc="nb" t-att-selected="nb == 1 and 'selected'"/> - </t> - </select> - </t> - <t t-id="tickets" t-call="website_event.ticket"> - <t t-set="name">Registration</t> - <t t-set="price"> - <span content="0" itemprop="price" class="font-weight-bold text-uppercase">Free</span> - </t> + + <t t-set="tickets" t-value="event.event_ticket_ids.filtered(lambda ticket: not ticket.is_expired)"/> + <!-- If some tickets expired and there is only one type left, we keep the same layout --> + <t t-if="len(event.event_ticket_ids) > 1"> + <div class="d-flex align-items-center py-2 pl-3 pr-2 border-bottom"> + <span t-if="not event.event_registrations_open" class="text-danger"> + <i class="fa fa-ban mr-2"/>Sold Out + </span> + <div class="ml-auto pr-3"> + <span t-if="event.is_participating" class="text-success ml-3"> + <i class="fa fa-check mr-2"/>Registered + </span> + </div> + <a href="#" role="button" class="btn btn-primary o_wevent_registration_btn collapsed" data-toggle="collapse" data-target="#o_wevent_tickets_collapse"> + Tickets + <span class="close">×</span> + </a> + </div> + <div id="o_wevent_tickets_collapse" class="collapse"> + <div t-foreach="tickets" t-as="ticket" class="row px-3 mx-0 bg-light border-bottom"> + <div class="col-8 py-3" itemscope="itemscope" itemtype="http://schema.org/Offer"> + <h5 itemprop="name" t-field="ticket.name" class="my-0"/> + <t t-if="ticket.description"> + <small t-field="ticket.description" class="text-muted py-2"/> + <br/> + </t> + <small t-if="ticket.end_sale_date and ticket.sale_available and not ticket.is_expired" class="text-muted mr-3" itemprop="availabilityEnds">Sales end on <span itemprop="priceValidUntil" t-field="ticket.end_sale_date"/></small> + <small t-if="ticket.start_sale_date and not ticket.sale_available and not ticket.is_expired" class="text-muted mr-3" itemprop="availabilityEnds">Sales start on <span itemprop="priceValidUntil" t-field="ticket.start_sale_date"/></small> + </div> + <div class="col-4 d-flex align-items-center"> + <div class="o_wevent_registration_multi_select"/> + <div class="w-auto ml-auto"> + <select t-if="not ticket.is_expired and ticket.sale_available" + t-attf-name="nb_register-#{ticket.id}" + class="custom-select"> + <t t-set="seats_max_ticket" t-value="(ticket.seats_availability == 'unlimited' or ticket.seats_available > 9) and 10 or ticket.seats_available + 1"/> + <t t-set="seats_max_event" t-value="(event.seats_availability == 'unlimited' or event.seats_available > 9) and 10 or event.seats_available + 1"/> + <t t-set="seats_max" t-value="min(seats_max_ticket, seats_max_event)"/> + <t t-foreach="range(0, seats_max)" t-as="nb"> + <option t-esc="nb" t-att-selected="len(ticket) == 0 and nb == 0 and 'selected'"/> + </t> + </select> + </div> + </div> + </div> + <div class="row no-gutters"> + <div class="col-md-4 offset-md-8 py-2 pl-md-0 pr-md-2"> + <button type="submit" class="btn btn-primary o_wait_lazy_js btn-block a-submit" t-att-disabled="not event.event_registrations_open or None" t-attf-id="#{event.id}">Register</button> + </div> + </div> + </div> </t> + <div t-else="" class="o_wevent_registration_single"> + <div class="row p-2 pl-3"> + <div class="col-lg-8 d-flex flex-columns align-items-center" itemscope="itemscope" itemtype="http://schema.org/Offer"> + <h6 itemprop="name" class="my-0 pr-3 border-right"> + <span t-if="tickets" t-field="tickets.name"/> + <span t-else="">Registration</span> + </h6> + + <small t-if="tickets.start_sale_date" class="text-muted ml-3" itemprop="availabilityEnds"> + Sales end on <span itemprop="priceValidUntil" t-field="tickets.end_sale_date"/> + </small> + <div class="ml-auto"> + <t t-if="event.event_registrations_open"> + <span class="font-weight-bold align-middle pr-2">Qty</span> + <link itemprop="availability" content="http://schema.org/InStock"/> + <select t-att-name="'nb_register-%s' % (tickets.id if tickets else 0)" class="w-auto custom-select"> + <t t-set="seats_max_ticket" t-value="(not tickets or tickets.seats_availability == 'unlimited' or tickets.seats_available > 9) and 10 or tickets.seats_available + 1"/> + <t t-set="seats_max_event" t-value="(event.seats_availability == 'unlimited' or event.seats_available > 9) and 10 or event.seats_available + 1"/> + <t t-set="seats_max" t-value="min(seats_max_ticket, seats_max_event) if tickets else seats_max_event"/> + <t t-foreach="range(0, seats_max)" t-as="nb"> + <option t-esc="nb" t-att-selected="nb == 1 and 'selected'"/> + </t> + </select> + </t> + <t t-else=""> + <span itemprop="availability" content="http://schema.org/SoldOut" class="text-danger"> + <i class="fa fa-ban mr-2"/>Sold Out + </span> + </t> + </div> + </div> + <div class="col-lg-4 pt-3 pt-lg-0 pl-2 pl-lg-0"> + <button type="submit" class="btn btn-primary o_wait_lazy_js btn-block a-submit" t-attf-id="#{event.id}">Register</button> + </div> + </div> + <div t-if="tickets.description" class="row mx-0"> + <div class="col-12 bg-200 rounded-bottom"> + <p itemprop="description" t-field="tickets.description" class="small my-2"/> + </div> + </div> + </div> </div> </form> <div t-elif="request.env.user.has_group('event.group_event_manager')" class="alert alert-info mb-5 o_website_event_configuration" role="status"> @@ -530,36 +628,6 @@ </div> </template> -<template id="ticket" name="Ticket offer template"> - <div class="row p-2 pl-3"> - <div class="col-lg-8 d-flex flex-columns align-items-center" itemscope="itemscope" itemtype="http://schema.org/Offer"> - <h6 t-raw="name" itemprop="name" class="my-0 pr-3"/> - <div class="border-left border-right px-3"><t t-raw="price"/></div> - <small t-raw="registration_end" class="text-muted ml-3" itemprop="availabilityEnds"/> - <div class="ml-auto"> - <t t-if="event.event_registrations_open"> - <span class="font-weight-bold align-middle pr-2">Qty</span> - <link itemprop="availability" content="http://schema.org/InStock"/> - <t t-raw="quantity"/> - </t> - <t t-else=""> - <span itemprop="availability" content="http://schema.org/SoldOut" class="text-danger"> - <i class="fa fa-ban mr-2"/>Sold Out - </span> - </t> - </div> - </div> - <div class="col-lg-4 pt-3 pt-lg-0 pl-2 pl-lg-0"> - <button type="submit" class="btn btn-primary o_wait_lazy_js btn-block a-submit" t-attf-id="#{event.id}">Register</button> - </div> - </div> - <div t-if="description" class="row mx-0"> - <div class="col-12 bg-200 rounded-bottom"> - <p itemprop="description" t-raw="description" class="small my-2"/> - </div> - </div> -</template> - <template id="registration_attendee_details" name="Registration Attendee Details"> <div id="modal_attendees_registration" class="modal fade" tabindex="-1" role="dialog"> <div class="modal-dialog modal-lg" role="document"> @@ -590,7 +658,7 @@ <label>Phone <small>(Optional)</small></label> <input class="form-control" type="tel" t-attf-name="#{counter}-phone"/> </div> - <input class="d-none" type="text" t-attf-name="#{counter}-ticket_id" t-attf-value="#{ticket['id']}"/> + <input class="d-none" type="text" t-attf-name="#{counter}-event_ticket_id" t-attf-value="#{ticket['id']}"/> </div> </div> </t> @@ -616,6 +684,7 @@ <thead class="bg-secondary"> <tr> <th>Name</th> + <th>Ticket</th> <th>E-mail</th> <th>Phone</th> <th>Reference</th> @@ -625,6 +694,7 @@ <t t-foreach="attendees" t-as="attendee"> <tr> <td><t t-if="attendee.name" t-esc="attendee.name"/><t t-else="">N/A</t></td> + <td><i class="fa fa-ticket"></i> <t t-if='attendee.event_ticket_id'><t t-esc="attendee.event_ticket_id.name"/></t><t t-if='not attendee.event_ticket_id'>N/A</t></td> <td><t t-if="attendee.email" t-esc="attendee.email"/><t t-else="">N/A</t></td> <td><t t-if="attendee.phone" t-esc="attendee.phone"/><t t-else="">N/A</t></td> <td><t t-esc="attendee.id"/></td> diff --git a/addons/website_event_questions/controllers/main.py b/addons/website_event_questions/controllers/main.py index 684999a26ff..bc8f98f1678 100644 --- a/addons/website_event_questions/controllers/main.py +++ b/addons/website_event_questions/controllers/main.py @@ -6,9 +6,9 @@ from odoo.addons.website_event.controllers.main import WebsiteEventController class WebsiteEvent(WebsiteEventController): - def _process_registration_details(self, details): + def _process_attendees_form(self, event, form_details): ''' Process data posted from the attendee details form. ''' - registrations = super(WebsiteEvent, self)._process_registration_details(details) + registrations = super(WebsiteEvent, self)._process_attendees_form(event, form_details) for registration in registrations: answer_ids = [] for key, value in registration.items(): diff --git a/addons/website_event_sale/controllers/main.py b/addons/website_event_sale/controllers/main.py index b47d2f0f2cc..d180679fb90 100644 --- a/addons/website_event_sale/controllers/main.py +++ b/addons/website_event_sale/controllers/main.py @@ -17,50 +17,46 @@ class WebsiteEventSaleController(WebsiteEventController): event = event.with_context(pricelist=pricelist.id) return super(WebsiteEventSaleController, self).event_register(event, **post) - def _process_tickets_details(self, data): - ticket_post = {} - for key, value in data.items(): - if not key.startswith('nb_register') or '-' not in key: - continue - items = key.split('-') - if len(items) < 2: - continue - ticket_post[int(items[1])] = int(value) - tickets = request.env['event.event.ticket'].browse(tuple(ticket_post)) - return [{'id': ticket.id, 'name': ticket.name, 'quantity': ticket_post[ticket.id], 'price': ticket.price} for ticket in tickets if ticket_post[ticket.id]] - - def _process_registration_details(self, details): - res = super(WebsiteEventSaleController, self)._process_registration_details(details) - for registration_vals in res: - registration_vals['event_ticket_id'] = int(registration_vals.pop('ticket_id')) if registration_vals.get('ticket_id') else False + def _process_tickets_form(self, event, form_details): + """ Add price information on ticket order """ + res = super(WebsiteEventSaleController, self)._process_tickets_form(event, form_details) + for item in res: + item['price'] = item['ticket']['price'] if item['ticket'] else 0 return res + def _create_attendees_from_registration_post(self, event, registration_data): + # we have at least one registration linked to a ticket -> sale mode activate + if any(info.get('event_ticket_id') for info in registration_data): + order = request.website.sale_get_order(force_create=1) + + order_attendee_ids = set() + for info in [r for r in registration_data if r.get('event_ticket_id')]: + ticket = request.env['event.event.ticket'].sudo().browse(info['event_ticket_id']) + cart_values = order.with_context(event_ticket_id=ticket.id, fixed_price=True)._cart_update(product_id=ticket.product_id.id, add_qty=1, registration_data=[info]) + order_attendee_ids |= set(cart_values.get('attendee_ids', [])) + + attendees_sudo = super(WebsiteEventSaleController, self)._create_attendees_from_registration_post(event, [r for r in registration_data if not r['event_ticket_id']]) + if order_attendee_ids: + attendees_sudo |= request.env['event.registration'].sudo().browse(order_attendee_ids) + + return attendees_sudo + @http.route() def registration_confirm(self, event, **post): - order = request.website.sale_get_order(force_create=1) - attendee_ids = set() + res = super(WebsiteEventSaleController, self).registration_confirm(event, **post) - registrations = self._process_registration_details(post) - for registration in registrations: - ticket = request.env['event.event.ticket'].sudo().browse(int(registration['event_ticket_id'])) - cart_values = order.with_context(event_ticket_id=ticket.id, fixed_price=True)._cart_update(product_id=ticket.product_id.id, add_qty=1, registration_data=[registration]) - attendee_ids |= set(cart_values.get('attendee_ids', [])) + registrations = self._process_attendees_form(event, post) - # free tickets -> order with amount = 0: auto-confirm, no checkout - if not order.amount_total: - order.action_confirm() # tde notsure: email sending ? - attendees = request.env['event.registration'].browse(list(attendee_ids)).sudo() - # clean context and session, then redirect to the confirmation page - request.website.sale_reset() - urls = event._get_event_resource_urls() - return request.render("website_event.registration_complete", { - 'attendees': attendees, - 'event': event, - 'google_url': urls.get('google_url'), - 'iCal_url': urls.get('iCal_url') - }) + # we have at least one registration linked to a ticket -> sale mode activate + if any(info['event_ticket_id'] for info in registrations): + order = request.website.sale_get_order(force_create=False) + if order.amount_total: + return request.redirect("/shop/checkout") + # free tickets -> order with amount = 0: auto-confirm, no checkout + elif order: + order.action_confirm() # tde notsure: email sending ? - return request.redirect("/shop/checkout") + return res def _add_event(self, event_name="New Event", context=None, **kwargs): product = request.env.ref('event_sale.product_product_event', raise_if_not_found=False) diff --git a/addons/website_event_sale/views/website_event_templates.xml b/addons/website_event_sale/views/website_event_templates.xml index 5f64d172c85..df1664a112c 100644 --- a/addons/website_event_sale/views/website_event_templates.xml +++ b/addons/website_event_sale/views/website_event_templates.xml @@ -1,130 +1,35 @@ <?xml version="1.0" encoding="utf-8"?> <odoo> -<template id="index" inherit_id="website_event.events_list" name="Event's Ticket"> - <xpath expr="//div[@t-foreach='event_ids']//footer" position="inside"> - <t t-if="event.event_registrations_open and event.event_ticket_ids"> - <span t-if="event.seats_availability == 'limited' and not event.seats_available" class="text-danger">Sold Out</span> - <span t-if="event.seats_availability == 'limited' and event.seats_available and event.seats_available <= ((event.seats_max or 0) / 4)" class="text-muted"> - <em>Only <t t-esc="event.seats_available"/> Remaining</em> - </span> - </t> - </xpath> -</template> - <template id="registration_template" inherit_id="website_event.registration_template"> - <xpath expr="//t[@t-id='tickets']" position="replace"> - <t t-set="tickets" t-value="event.event_ticket_ids.filtered(lambda ticket: not ticket.is_expired)"/> - <t t-if="len(event.event_ticket_ids) > 1"> <!-- If some tickets expired and there is only one type left, we keep the same layout --> - <div class="d-flex align-items-center py-2 pl-3 pr-2 border-bottom"> - <span t-if="not event.event_registrations_open" class="text-danger"> - <i class="fa fa-ban mr-2"/>Sold Out - </span> - <div class="ml-auto pr-3"> - <span t-if="event.is_participating" class="text-success ml-3"> - <i class="fa fa-check mr-2"/>Registered - </span> - </div> - <a href="#" role="button" class="btn btn-primary o_wevent_registration_btn collapsed" data-toggle="collapse" data-target="#o_wevent_tickets_collapse"> - Tickets - <span class="close">×</span> - </a> - </div> - <div id="o_wevent_tickets_collapse" class="collapse"> - <div t-foreach="tickets" t-as="ticket" class="row mx-0 bg-light border-bottom"> - <div class="col-md-8 py-3" itemscope="itemscope" itemtype="http://schema.org/Offer"> - <h5 itemprop="name" t-field="ticket.name" class="my-0"/> - <small t-if="ticket.end_sale_date and ticket.sale_available and not ticket.is_expired" class="text-muted mr-3" itemprop="availabilityEnds">Sales end on <span itemprop="priceValidUntil" t-field="ticket.end_sale_date"/></small> - <small t-if="ticket.start_sale_date and not ticket.sale_available and not ticket.is_expired" class="text-muted mr-3" itemprop="availabilityEnds">Sales start on <span itemprop="priceValidUntil" t-field="ticket.start_sale_date"/></small> - </div> - <div class="col-md-4 py-3 pl-md-0"> - <div class="d-flex align-items-center"> - <t t-if="ticket.price or editable"> - <t t-if="(ticket.price-website.get_current_pricelist().currency_id._convert(ticket.price_reduce, event.company_id.sudo().currency_id, event.company_id, datetime.date.today())) > 1 and website.get_current_pricelist().discount_policy == 'without_discount'"> - <del class="text-danger mr-1" t-field="ticket.price" t-options="{'widget': 'monetary', 'from_currency': event.company_id.sudo().currency_id, 'display_currency': website.get_current_pricelist().currency_id}"/> - </t> - <span t-field="ticket.price_reduce" t-options="{'widget': 'monetary', 'display_currency': website.pricelist_id.currency_id}" groups="account.group_show_line_subtotals_tax_excluded"/> - <span t-field="ticket.price_reduce_taxinc" t-options="{'widget': 'monetary', 'display_currency': website.pricelist_id.currency_id}" groups="account.group_show_line_subtotals_tax_included"/> - <span itemprop="price" class="d-none" t-esc="ticket.price"/> - <span itemprop="priceCurrency" class="d-none" t-esc="website.pricelist_id.currency_id.name"/> - </t> - <span t-if="not ticket.price and not editable" class="font-weight-bold text-uppercase">Free</span> - <t t-if="not ticket.is_expired and ticket.sale_available"> - <select t-attf-name="nb_register-#{ticket.id}" class="w-auto ml-auto custom-select"> - <t t-set="seats_max_ticket" t-value="(ticket.seats_availability == 'unlimited' or ticket.seats_available > 9) and 10 or ticket.seats_available + 1"/> - <t t-set="seats_max_event" t-value="(event.seats_availability == 'unlimited' or event.seats_available > 9) and 10 or event.seats_available + 1"/> - <t t-set="seats_max" t-value="min(seats_max_ticket, seats_max_event)"/> - <t t-foreach="range(0, seats_max)" t-as="nb"> - <option t-esc="nb" t-att-selected="len(ticket) == 0 and nb == 0 and 'selected'"/> - </t> - </select> - </t> - </div> - </div> - <div t-if="ticket.product_id.description_sale" class="col-12"> - <p itemprop="description" t-field="ticket.product_id.description_sale" class="small py-2 border-top"/> - </div> - </div> - <div class="row no-gutters"> - <div class="col-md-4 offset-md-8 py-2 pl-md-0 pr-md-2"> - <button type="submit" class="btn btn-primary o_wait_lazy_js btn-block a-submit" t-att-disabled="not event.event_registrations_open or None" t-attf-id="#{event.id}">Register</button> - </div> - </div> - </div> - </t> - <t t-else=""> - <t t-call="website_event.ticket"> - <t t-set="name"><span t-field="tickets.name"/></t> - <t t-set="price"> - <t t-if="tickets.price or editable"> - <t t-if="(tickets.price-website.get_current_pricelist().currency_id._convert(tickets.price_reduce, event.company_id.sudo().currency_id, event.company_id, datetime.date.today())) > 1 and website.get_current_pricelist().discount_policy == 'without_discount'"> - <del class="text-danger mr-1" t-field="tickets.price" t-options="{'widget': 'monetary', 'from_currency': event.company_id.sudo().currency_id, 'display_currency': website.get_current_pricelist().currency_id}"/> - </t> - <span t-field="tickets.price_reduce" t-options="{'widget': 'monetary', 'display_currency': website.pricelist_id.currency_id}" groups="account.group_show_line_subtotals_tax_excluded"/> - <span t-field="tickets.price_reduce_taxinc" t-options="{'widget': 'monetary', 'display_currency': website.pricelist_id.currency_id}" groups="account.group_show_line_subtotals_tax_included"/> - <span itemprop="price" class="d-none" t-esc="tickets.price"/> - <span itemprop="priceCurrency" class="d-none" t-esc="website.pricelist_id.currency_id.name"/> - </t> - <span t-if="not tickets.price and not editable" class="font-weight-bold text-uppercase">Free</span> - </t> - <t t-if="tickets.product_id.description_sale" t-set="description"> - <span t-field="tickets.product_id.description_sale"/> - </t> - <t t-set="registration_end"> - <t t-if="tickets.start_sale_date">Sales end on <span itemprop="priceValidUntil" t-field="tickets.end_sale_date"/></t> - </t> - <t t-if="not tickets.is_expired and tickets.sale_available" t-set="quantity"> - <select t-attf-name="nb_register-#{tickets.id}" class="w-auto custom-select"> - <t t-set="seats_max_ticket" t-value="(tickets.seats_availability == 'unlimited' or tickets.seats_available > 9) and 10 or tickets.seats_available + 1"/> - <t t-set="seats_max_event" t-value="(event.seats_availability == 'unlimited' or event.seats_available > 9) and 10 or event.seats_available + 1"/> - <t t-set="seats_max" t-value="min(seats_max_ticket, seats_max_event)"/> - <t t-foreach="range(0, seats_max)" t-as="nb"> - <option t-esc="nb" t-att-selected="len(tickets) == 1 and nb == 1 and 'selected'"/> - </t> - </select> - </t> + <!-- Add price information on tickets (multi tickets, aka in collapse) --> + <xpath expr="//div[hasclass('o_wevent_registration_multi_select')]" position="inside"> + <t t-if="ticket.price"> + <t t-if="(ticket.price-website.get_current_pricelist().currency_id._convert(ticket.price_reduce, event.company_id.sudo().currency_id, event.company_id, datetime.date.today())) > 1 and website.get_current_pricelist().discount_policy == 'without_discount'"> + <del class="text-danger mr-1" t-field="ticket.price" t-options="{'widget': 'monetary', 'from_currency': event.company_id.sudo().currency_id, 'display_currency': website.get_current_pricelist().currency_id}"/> </t> + <span t-field="ticket.price_reduce" t-options="{'widget': 'monetary', 'display_currency': website.pricelist_id.currency_id}" groups="account.group_show_line_subtotals_tax_excluded"/> + <span t-field="ticket.price_reduce_taxinc" t-options="{'widget': 'monetary', 'display_currency': website.pricelist_id.currency_id}" groups="account.group_show_line_subtotals_tax_included"/> + <span itemprop="price" class="d-none" t-esc="ticket.price"/> + <span itemprop="priceCurrency" class="d-none" t-esc="website.pricelist_id.currency_id.name"/> </t> + <span t-else="" class="font-weight-bold text-uppercase">Free</span> </xpath> - <xpath expr="//form[@id='registration_form']" position="attributes"> - <attribute name="t-if">event.event_registrations_open and not all([ticket.is_expired for ticket in event.event_ticket_ids])</attribute> - </xpath> - <xpath expr="//form[@id='registration_form']" position="before"> - <div t-if="event.start_sale_date and event.start_sale_date > datetime.date.today() and not event.event_registrations_open" class="alert alert-info mb-5" role="status"> - <em >Ticket Sales starting on <t t-esc="event.start_sale_date"/></em> + <!-- Add price information on tickets (mono ticket, aka not in collapse) --> + <xpath expr="//div[hasclass('o_wevent_registration_single')]//h6" position="after"> + <div class="border-right px-3"> + <t t-if="tickets.price"> + <t t-if="(tickets.price-website.get_current_pricelist().currency_id._convert(tickets.price_reduce, event.company_id.sudo().currency_id, event.company_id, datetime.date.today())) > 1 and website.get_current_pricelist().discount_policy == 'without_discount'"> + <del class="text-danger mr-1" t-field="tickets.price" t-options="{'widget': 'monetary', 'from_currency': event.company_id.sudo().currency_id, 'display_currency': website.get_current_pricelist().currency_id}"/> + </t> + <span t-field="tickets.price_reduce" t-options="{'widget': 'monetary', 'display_currency': website.pricelist_id.currency_id}" groups="account.group_show_line_subtotals_tax_excluded"/> + <span t-field="tickets.price_reduce_taxinc" t-options="{'widget': 'monetary', 'display_currency': website.pricelist_id.currency_id}" groups="account.group_show_line_subtotals_tax_included"/> + <span itemprop="price" class="d-none" t-esc="tickets.price"/> + <span itemprop="priceCurrency" class="d-none" t-esc="website.pricelist_id.currency_id.name"/> + </t> + <span t-else="" class="font-weight-bold text-uppercase">Free</span> </div> </xpath> </template> - -<!-- Add the ticket name on the registration complete page. --> -<template id="registration_complete_inherit_website_event_sale" inherit_id="website_event.registration_complete" name="Sale Registration Completed"> - <xpath expr="//thead/tr/th[1]" position="after"> - <th>Ticket</th> - </xpath> - <xpath expr="//tbody/t/tr/td[1]" position="after"> - <td><i class="fa fa-ticket"></i> <t t-if='attendee.event_ticket_id'><t t-esc="attendee.event_ticket_id.name"/></t><t t-if='not attendee.event_ticket_id'>N/A</t></td> - </xpath> -</template> - </odoo> |
