summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/website_event/controllers/main.py78
-rw-r--r--addons/website_event/static/src/scss/website_event.scss6
-rw-r--r--addons/website_event/views/event_templates.xml160
-rw-r--r--addons/website_event_questions/controllers/main.py4
-rw-r--r--addons/website_event_sale/controllers/main.py70
-rw-r--r--addons/website_event_sale/views/website_event_templates.xml141
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 &lt;5 or event.seats_available &lt;= ((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 &gt; 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 &gt; 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) &gt; 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 &gt; 9) and 10 or ticket.seats_available + 1"/>
+ <t t-set="seats_max_event" t-value="(event.seats_availability == 'unlimited' or event.seats_available &gt; 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 &gt; 9) and 10 or tickets.seats_available + 1"/>
+ <t t-set="seats_max_event" t-value="(event.seats_availability == 'unlimited' or event.seats_available &gt; 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 &lt;= ((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) &gt; 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())) &gt; 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 &gt; 9) and 10 or ticket.seats_available + 1"/>
- <t t-set="seats_max_event" t-value="(event.seats_availability == 'unlimited' or event.seats_available &gt; 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())) &gt; 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 &gt; 9) and 10 or tickets.seats_available + 1"/>
- <t t-set="seats_max_event" t-value="(event.seats_availability == 'unlimited' or event.seats_available &gt; 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())) &gt; 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 &gt; 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())) &gt; 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>