[IMP] website_event(_sale): adds new identification questions
This commit changes the way the identification questions (name, email, phone) are asked when registering to an event. They aren't hardcoded anymore and can be created per event the same way other questions can be. They can be set as mandatory or not and the order can be changed. One can now also ask for the attendee company name. Task-3056380 closes odoo/odoo#112164 Related: odoo/upgrade#4313 Signed-off-by: Warnon Aurélien (awa) <awa@odoo.com>
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
<field name="description">Sent automatically to someone after they registered to an event</field>
|
||||
<field name="body_html" type="html">
|
||||
<div>
|
||||
Dear <t t-out="object.name or ''">Oscar Morgan</t>,<br/>
|
||||
Dear <t t-out="object.name or 'Guest'"/>,<br/>
|
||||
Thank you for your inquiry.<br/>
|
||||
Here is your badge for the event <t t-out="object.event_id.name or ''">OpenWood Collection Online Reveal</t>.<br/>
|
||||
If you have any questions, please let us know.
|
||||
@@ -50,7 +50,7 @@
|
||||
<tr><td valign="middle">
|
||||
<span style="font-size: 10px;">Your registration</span><br/>
|
||||
<span style="font-size: 20px; font-weight: bold;">
|
||||
<t t-out="object.name or ''">Oscar Morgan</t>
|
||||
<t t-out="object.name or 'Guest'"/>
|
||||
</span>
|
||||
</td><td valign="middle" align="right">
|
||||
<t t-if="is_online">
|
||||
@@ -75,7 +75,7 @@
|
||||
<table width="590" border="0" cellpadding="0" cellspacing="0" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<div>
|
||||
Hello <t t-out="object.name or ''">Oscar Morgan</t>,<br/>
|
||||
Hello <t t-out="object.name or 'Guest'"/>,<br/>
|
||||
We are happy to confirm your registration to the event
|
||||
<t t-if="is_online">
|
||||
<a t-att-href="object.event_id.website_url" style="color:#875A7B;text-decoration:none;" t-out="object.event_id.name or ''">OpenWood Collection Online Reveal</a>
|
||||
@@ -83,7 +83,7 @@
|
||||
<t t-else="">
|
||||
<strong t-out="object.event_id.name or ''">OpenWood Collection Online Reveal</strong>
|
||||
</t>
|
||||
for attendee <t t-out="object.name or ''">Oscar Morgan</t>.
|
||||
for attendee <t t-out="object.name or 'Guest'"/>.
|
||||
</div>
|
||||
<div>
|
||||
<br />
|
||||
@@ -282,7 +282,7 @@
|
||||
<table width="590" border="0" cellpadding="0" cellspacing="0" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
|
||||
<tr><td valign="middle">
|
||||
<span style="font-size: 10px;">Your registration</span><br/>
|
||||
<span style="font-size: 20px; font-weight: bold;" t-out="object.name or ''">Oscar Morgan</span>
|
||||
<span style="font-size: 20px; font-weight: bold;" t-out="object.name or 'Guest'"/>
|
||||
</td><td valign="middle" align="right">
|
||||
<t t-if="is_online">
|
||||
<a t-attf-href="{{ object.event_id.website_url }}"
|
||||
@@ -306,7 +306,7 @@
|
||||
<table width="590" border="0" cellpadding="0" cellspacing="0" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
|
||||
<tr><td valign="top" style="font-size: 14px;">
|
||||
<div>
|
||||
Hello <t t-out="object.name or ''">Oscar Morgan</t>,<br/>
|
||||
Hello <t t-out="object.name or 'Guest'"/>,<br/>
|
||||
We are excited to remind you that the event
|
||||
<t t-if="is_online">
|
||||
<a t-att-href="object.event_id.website_url" style="color:#875A7B;text-decoration:none;" t-out="object.event_id.name or ''">OpenWood Collection Online Reveal</a>
|
||||
|
||||
@@ -34,6 +34,8 @@ class EventRegistration(models.Model):
|
||||
email = fields.Char(string='Email', compute='_compute_email', readonly=False, store=True, tracking=11)
|
||||
phone = fields.Char(string='Phone', compute='_compute_phone', readonly=False, store=True, tracking=12)
|
||||
mobile = fields.Char(string='Mobile', compute='_compute_mobile', readonly=False, store=True, tracking=13)
|
||||
company_name = fields.Char(
|
||||
string='Company Name', compute='_compute_company_name', readonly=False, store=True, tracking=14)
|
||||
# organization
|
||||
date_closed = fields.Datetime(
|
||||
string='Attended Date', compute='_compute_date_closed',
|
||||
@@ -86,6 +88,15 @@ class EventRegistration(models.Model):
|
||||
fnames=['mobile']
|
||||
).get('mobile') or False
|
||||
|
||||
@api.depends('partner_id')
|
||||
def _compute_company_name(self):
|
||||
for registration in self:
|
||||
if not registration.company_name and registration.partner_id:
|
||||
registration.company_name = registration._synchronize_partner_values(
|
||||
registration.partner_id,
|
||||
fnames=['company_name']
|
||||
).get('company_name') or False
|
||||
|
||||
@api.depends('state')
|
||||
def _compute_date_closed(self):
|
||||
for registration in self:
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<field name="email" optional="show"/>
|
||||
<field name="phone" optional="show"/>
|
||||
<field name="mobile" optional="hide"/>
|
||||
<field name="company_name" optional="hide"/>
|
||||
<field name="event_id" invisible="context.get('default_event_id')"/>
|
||||
<field name="event_ticket_id" domain="[('event_id', '=', event_id)]"/>
|
||||
<field name="activity_ids" widget="list_activity"/>
|
||||
@@ -64,6 +65,7 @@
|
||||
<field name="email"/>
|
||||
<field name="phone" class="o_force_ltr" widget="phone" options="{'enable_sms': false}"/>
|
||||
<field name="mobile" class="o_force_ltr" widget="phone"/>
|
||||
<field name="company_name" placeholder='e.g. "Azure Interior"'/>
|
||||
</group>
|
||||
<group string="Event Information" name="event">
|
||||
<field class="o_text_overflow" name="event_id" attrs="{'readonly': [('state', '!=', 'draft')]}"
|
||||
|
||||
@@ -16,29 +16,29 @@ var registerSteps = [{
|
||||
run: 'click',
|
||||
}, {
|
||||
content: "Fill attendees details",
|
||||
trigger: 'form[id="attendee_registration"] .btn:contains("Continue")',
|
||||
trigger: 'form[id="attendee_registration"] .btn[type=submit]',
|
||||
run: function () {
|
||||
$("input[name='1-name']").val("Raoulette Poiluchette");
|
||||
$("input[name='1-phone']").val("0456112233");
|
||||
$("input[name='1-email']").val("raoulette@example.com");
|
||||
$("div[name*='Question1'] select[name*='question_answer-1']").val($("select[name*='question_answer-1'] option:contains('Q1-Answer2')").val());
|
||||
$("div[name*='Question2'] select[name*='question_answer-1']").val($("select[name*='question_answer-1'] option:contains('Q2-Answer1')").val());
|
||||
$("input[name='2-name']").val("Michel Tractopelle");
|
||||
$("input[name='2-phone']").val("0456332211");
|
||||
$("input[name='2-email']").val("michel@example.com");
|
||||
$("div[name*='Question1'] select[name*='question_answer-2']").val($("select[name*='question_answer-2'] option:contains('Q1-Answer1')").val());
|
||||
$("div[name*='Question2'] select[name*='question_answer-2']").val($("select[name*='question_answer-2'] option:contains('Q2-Answer2')").val());
|
||||
$("input[name='3-name']").val("Hubert Boitaclous");
|
||||
$("input[name='3-phone']").val("0456995511");
|
||||
$("input[name='3-email']").val("hubert@example.com");
|
||||
$("div[name*='Question1'] select[name*='question_answer-3']").val($("select[name*='question_answer-3'] option:contains('Q1-Answer2')").val());
|
||||
$("div[name*='Question2'] select[name*='question_answer-3']").val($("select[name*='question_answer-3'] option:contains('Q2-Answer2')").val());
|
||||
$("input[name*='1-name']").val("Raoulette Poiluchette");
|
||||
$("input[name*='1-phone']").val("0456112233");
|
||||
$("input[name*='1-email']").val("raoulette@example.com");
|
||||
$("div[name*='Question1'] select[name*='1-simple_choice']").val($("select[name*='1-simple_choice'] option:contains('Q1-Answer2')").val());
|
||||
$("div[name*='Question2'] select[name*='1-simple_choice']").val($("select[name*='1-simple_choice'] option:contains('Q2-Answer1')").val());
|
||||
$("input[name*='2-name']").val("Michel Tractopelle");
|
||||
$("input[name*='2-phone']").val("0456332211");
|
||||
$("input[name*='2-email']").val("michel@example.com");
|
||||
$("div[name*='Question1'] select[name*='2-simple_choice']").val($("select[name*='2-simple_choice'] option:contains('Q1-Answer1')").val());
|
||||
$("div[name*='Question2'] select[name*='2-simple_choice']").val($("select[name*='2-simple_choice'] option:contains('Q2-Answer2')").val());
|
||||
$("input[name*='3-name']").val("Hubert Boitaclous");
|
||||
$("input[name*='3-phone']").val("0456995511");
|
||||
$("input[name*='3-email']").val("hubert@example.com");
|
||||
$("div[name*='Question1'] select[name*='3-simple_choice']").val($("select[name*='3-simple_choice'] option:contains('Q1-Answer2')").val());
|
||||
$("div[name*='Question2'] select[name*='3-simple_choice']").val($("select[name*='3-simple_choice'] option:contains('Q2-Answer2')").val());
|
||||
$("textarea[name*='question_answer']").text("Random answer from random guy");
|
||||
},
|
||||
}, {
|
||||
content: "Validate attendees details",
|
||||
extra_trigger: "input[name='1-name'], input[name='2-name'], input[name='3-name']",
|
||||
trigger: 'button:contains("Continue")',
|
||||
extra_trigger: "input[name*='1-name'], input[name*='2-name'], input[name*='3-name']",
|
||||
trigger: 'button[type=submit]',
|
||||
run: 'click',
|
||||
}, {
|
||||
content: "Address filling",
|
||||
|
||||
@@ -91,22 +91,22 @@ var registerSteps = [{
|
||||
run: 'click',
|
||||
}, {
|
||||
content: "Fill attendees details",
|
||||
trigger: 'form[id="attendee_registration"] .btn:contains("Continue")',
|
||||
trigger: 'form[id="attendee_registration"] .btn[type=submit]',
|
||||
run: function () {
|
||||
$("input[name='1-name']").val("Raoulette Poiluchette");
|
||||
$("input[name='1-phone']").val("0456112233");
|
||||
$("input[name='1-email']").val("raoulette@example.com");
|
||||
$("select[name*='question_answer-1']").val($("select[name*='question_answer-1'] option:contains('Consumers')").val());
|
||||
$("input[name='2-name']").val("Michel Tractopelle");
|
||||
$("input[name='2-phone']").val("0456332211");
|
||||
$("input[name='2-email']").val("michel@example.com");
|
||||
$("select[name*='question_answer-2']").val($("select[name*='question_answer-1'] option:contains('Research')").val());
|
||||
$("textarea[name*='question_answer']").text("An unicorn told me about you. I ate it afterwards.");
|
||||
$("input[name*='1-name']").val("Raoulette Poiluchette");
|
||||
$("input[name*='1-phone']").val("0456112233");
|
||||
$("input[name*='1-email']").val("raoulette@example.com");
|
||||
$("select[name*='1-simple_choice']").val($("select[name*='1-simple_choice'] option:contains('Consumers')").val());
|
||||
$("input[name*='2-name']").val("Michel Tractopelle");
|
||||
$("input[name*='2-phone']").val("0456332211");
|
||||
$("input[name*='2-email']").val("michel@example.com");
|
||||
$("select[name*='2-simple_choice']").val($("select[name*='1-simple_choice'] option:contains('Research')").val());
|
||||
$("textarea[name*='text_box']").text("An unicorn told me about you. I ate it afterwards.");
|
||||
},
|
||||
}, {
|
||||
content: "Validate attendees details",
|
||||
extra_trigger: "input[name='1-name'], input[name='2-name'], input[name='3-name']",
|
||||
trigger: 'button:contains("Continue")',
|
||||
extra_trigger: "input[name*='1-name'], input[name*='2-name'], input[name*='3-name']",
|
||||
trigger: 'button[type=submit]',
|
||||
run: 'click',
|
||||
}, {
|
||||
trigger: 'div.o_wereg_confirmed_attendees span:contains("Raoulette Poiluchette")',
|
||||
|
||||
@@ -128,7 +128,7 @@ class TestEventPerformance(EventPerformanceCase):
|
||||
has_social = 'social_menu' in self.env['event.event'] # otherwise view may crash in enterprise
|
||||
|
||||
# no type, website
|
||||
with freeze_time(self.reference_now), self.assertQueryCount(event_user=449): # tef 398 / com 399
|
||||
with freeze_time(self.reference_now), self.assertQueryCount(event_user=429): # tef 379 / com 380
|
||||
self.env.cr._now = self.reference_now # force create_date to check schedulers
|
||||
# Require for `website_menu` to be visible
|
||||
# <div name="event_menu_configuration" groups="base.group_no_one">
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import babel.dates
|
||||
import pytz
|
||||
import re
|
||||
import werkzeug
|
||||
|
||||
from ast import literal_eval
|
||||
from collections import defaultdict
|
||||
from datetime import datetime, timedelta
|
||||
from dateutil.parser import parse
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from werkzeug.datastructures import OrderedMultiDict
|
||||
from werkzeug.exceptions import NotFound
|
||||
|
||||
from odoo import fields, http, _
|
||||
from odoo.addons.http_routing.models.ir_http import slug
|
||||
from odoo.addons.website.controllers.main import QueryURL
|
||||
from odoo.http import request
|
||||
from odoo.osv import expression
|
||||
@@ -270,51 +264,65 @@ class WebsiteEventController(http.Controller):
|
||||
if int(ticket_id) not in event.event_ticket_ids.ids and len(event.event_ticket_ids.ids) > 0:
|
||||
raise UserError(_("This ticket is not available for sale for this event"))
|
||||
registrations = {}
|
||||
global_values = {}
|
||||
general_answer_ids = []
|
||||
general_identification_answers = {}
|
||||
# as we may have several questions populating the same field (e.g: the phone)
|
||||
# we use this to hold the fields that have already been handled
|
||||
# goal is to use the answer to the first question of every 'type' (aka name / phone / email / company name)
|
||||
already_handled_fields_data = {}
|
||||
for key, value in form_details.items():
|
||||
if 'question_answer' in key and value:
|
||||
dummy, registration_index, question_id = key.split('-')
|
||||
question_sudo = request.env['event.question'].browse(int(question_id))
|
||||
answer_values = None
|
||||
if question_sudo.question_type == 'simple_choice':
|
||||
answer_values = {
|
||||
'question_id': int(question_id),
|
||||
'value_answer_id': int(value)
|
||||
}
|
||||
elif question_sudo.question_type == 'text_box':
|
||||
answer_values = {
|
||||
'question_id': int(question_id),
|
||||
'value_text_box': value
|
||||
}
|
||||
if not value:
|
||||
continue
|
||||
|
||||
if answer_values and not int(registration_index):
|
||||
general_answer_ids.append((0, 0, answer_values))
|
||||
elif answer_values:
|
||||
registrations.setdefault(registration_index, dict())\
|
||||
.setdefault('registration_answer_ids', list()).append((0, 0, answer_values))
|
||||
else:
|
||||
counter, attr_name = key.split('-', 1)
|
||||
field_name = attr_name.split('-')[0]
|
||||
key_values = key.split('-')
|
||||
# Special case for handling event_ticket_id data that holds only 2 values
|
||||
if len(key_values) == 2:
|
||||
registration_index, field_name = key_values
|
||||
if field_name not in registration_fields:
|
||||
continue
|
||||
elif isinstance(registration_fields[field_name], (fields.Many2one, fields.Integer)):
|
||||
value = int(value) or False # 0 is considered as a void many2one aka False
|
||||
else:
|
||||
value = value
|
||||
registrations.setdefault(registration_index, dict())[field_name] = int(value)
|
||||
continue
|
||||
|
||||
if counter == '0':
|
||||
global_values[attr_name] = value
|
||||
registration_index, question_type, question_id = key_values
|
||||
answer_values = None
|
||||
if question_type == 'simple_choice':
|
||||
answer_values = {
|
||||
'question_id': int(question_id),
|
||||
'value_answer_id': int(value)
|
||||
}
|
||||
else:
|
||||
answer_values = {
|
||||
'question_id': int(question_id),
|
||||
'value_text_box': value
|
||||
}
|
||||
|
||||
if answer_values and not int(registration_index):
|
||||
general_answer_ids.append((0, 0, answer_values))
|
||||
elif answer_values:
|
||||
registrations.setdefault(registration_index, dict())\
|
||||
.setdefault('registration_answer_ids', list()).append((0, 0, answer_values))
|
||||
|
||||
if question_type in ('name', 'email', 'phone', 'company_name')\
|
||||
and question_type not in already_handled_fields_data.get(registration_index, []):
|
||||
if question_type not in registration_fields:
|
||||
continue
|
||||
|
||||
field_name = question_type
|
||||
already_handled_fields_data.setdefault(registration_index, list()).append(field_name)
|
||||
|
||||
if not int(registration_index):
|
||||
general_identification_answers[field_name] = value
|
||||
else:
|
||||
registrations.setdefault(counter, dict())[attr_name] = value
|
||||
for key, value in global_values.items():
|
||||
for registration in registrations.values():
|
||||
registration[key] = value
|
||||
registrations.setdefault(registration_index, dict())[field_name] = value
|
||||
|
||||
if general_answer_ids:
|
||||
for registration in registrations.values():
|
||||
registration.setdefault('registration_answer_ids', list()).extend(general_answer_ids)
|
||||
|
||||
if general_identification_answers:
|
||||
for registration in registrations.values():
|
||||
registration.update(general_identification_answers)
|
||||
|
||||
return list(registrations.values())
|
||||
|
||||
def _create_attendees_from_registration_post(self, event, registration_data):
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- Event Type -->
|
||||
<record id="event.event_type_0" model="event.type">
|
||||
<field name="question_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'title': 'Name', 'question_type': 'name', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Email', 'question_type': 'email', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Phone', 'question_type': 'phone'})]"/>
|
||||
</record>
|
||||
|
||||
<record id="event.event_type_1" model="event.type">
|
||||
<field name="question_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'title': 'Name', 'question_type': 'name', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Email', 'question_type': 'email', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Phone', 'question_type': 'phone'})]"/>
|
||||
</record>
|
||||
|
||||
<record id="event.event_type_2" model="event.type">
|
||||
<field name="question_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'title': 'Name', 'question_type': 'name', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Email', 'question_type': 'email', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Phone', 'question_type': 'phone'})]"/>
|
||||
</record>
|
||||
|
||||
<!-- Event Event -->
|
||||
<record id="event.event_0" model="event.event">
|
||||
<field name="website_published" eval="True"/>
|
||||
<field name="subtitle">Get Inspired • Stay Connected • Have Fun</field>
|
||||
@@ -36,6 +60,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</field>
|
||||
<field name="question_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'title': 'Name', 'question_type': 'name', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Email', 'question_type': 'email', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Phone', 'question_type': 'phone'})]"/>
|
||||
</record>
|
||||
|
||||
<record id="event.event_1" model="event.event">
|
||||
@@ -57,6 +85,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</field>
|
||||
<field name="question_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'title': 'Name', 'question_type': 'name', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Email', 'question_type': 'email', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Phone', 'question_type': 'phone'})]"/>
|
||||
</record>
|
||||
|
||||
<record id="event.event_2" model="event.event">
|
||||
@@ -99,6 +131,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</field>
|
||||
<field name="question_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'title': 'Name', 'question_type': 'name', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Email', 'question_type': 'email', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Phone', 'question_type': 'phone'})]"/>
|
||||
</record>
|
||||
|
||||
<record id="event.event_3" model="event.event">
|
||||
@@ -117,12 +153,20 @@
|
||||
</div>
|
||||
</div>
|
||||
</field>
|
||||
<field name="question_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'title': 'Name', 'question_type': 'name', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Email', 'question_type': 'email', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Phone', 'question_type': 'phone'})]"/>
|
||||
</record>
|
||||
|
||||
<record id="event.event_4" model="event.event">
|
||||
<field name="website_published" eval="True"/>
|
||||
<field name="subtitle">Discover how to grow a sustainable business with our experts.</field>
|
||||
<field name="cover_properties">{"background-image": "url('/website_event/static/src/img/event_cover_4.jpg')", "resize_class": "o_record_has_cover o_half_screen_height", "opacity": "0.4"}</field>
|
||||
<field name="question_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'title': 'Name', 'question_type': 'name', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Email', 'question_type': 'email', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Phone', 'question_type': 'phone'})]"/>
|
||||
</record>
|
||||
|
||||
<record id="event.event_5" model="event.event">
|
||||
@@ -142,11 +186,19 @@
|
||||
</div>
|
||||
</div>
|
||||
</field>
|
||||
<field name="question_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'title': 'Name', 'question_type': 'name', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Email', 'question_type': 'email', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Phone', 'question_type': 'phone'})]"/>
|
||||
</record>
|
||||
|
||||
<record id="event.event_6" model="event.event">
|
||||
<field name="website_published" eval="False"/>
|
||||
<field name="cover_properties">{"background-image": "none", "background-color": "secondary", "opacity": ""}</field>
|
||||
<field name="question_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'title': 'Name', 'question_type': 'name', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Email', 'question_type': 'email', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Phone', 'question_type': 'phone'})]"/>
|
||||
</record>
|
||||
|
||||
<record id="event.event_7" model="event.event">
|
||||
@@ -169,6 +221,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</field>
|
||||
<field name="question_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'title': 'Name', 'question_type': 'name', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Email', 'question_type': 'email', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': 'Phone', 'question_type': 'phone'})]"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from ast import literal_eval
|
||||
from collections import defaultdict
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import json
|
||||
import werkzeug.urls
|
||||
@@ -36,6 +35,9 @@ class Event(models.Model):
|
||||
})
|
||||
return res
|
||||
|
||||
def _default_question_ids(self):
|
||||
return self.env['event.type']._default_question_ids()
|
||||
|
||||
# description
|
||||
subtitle = fields.Char('Event Subtitle', translate=True)
|
||||
# registration
|
||||
@@ -219,7 +221,7 @@ class Event(models.Model):
|
||||
questions_tokeep_ids = []
|
||||
for event in self:
|
||||
if not event.event_type_id and not event.question_ids:
|
||||
event.question_ids = False
|
||||
event.question_ids = self._default_question_ids()
|
||||
continue
|
||||
|
||||
if questions_tokeep_ids:
|
||||
|
||||
@@ -14,7 +14,12 @@ class EventQuestion(models.Model):
|
||||
title = fields.Char(required=True, translate=True)
|
||||
question_type = fields.Selection([
|
||||
('simple_choice', 'Selection'),
|
||||
('text_box', 'Text Input')], default='simple_choice', string="Question Type", required=True)
|
||||
('text_box', 'Text Input'),
|
||||
('name', 'Name'),
|
||||
('email', 'Email'),
|
||||
('phone', 'Phone'),
|
||||
('company_name', 'Company'),
|
||||
], default='simple_choice', string="Question Type", required=True)
|
||||
event_type_id = fields.Many2one('event.type', 'Event Type', ondelete='cascade')
|
||||
event_id = fields.Many2one('event.event', 'Event', ondelete='cascade')
|
||||
answer_ids = fields.One2many('event.question.answer', 'question_id', "Answers", copy=True)
|
||||
|
||||
@@ -12,4 +12,4 @@ class EventRegistration(models.Model):
|
||||
registration_answer_ids = fields.One2many('event.registration.answer', 'registration_id', string='Attendee Answers')
|
||||
|
||||
def _get_website_registration_allowed_fields(self):
|
||||
return {'name', 'phone', 'email', 'mobile', 'event_id', 'partner_id', 'event_ticket_id'}
|
||||
return {'name', 'phone', 'email', 'mobile', 'company_name', 'event_id', 'partner_id', 'event_ticket_id'}
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import api, fields, models, _
|
||||
|
||||
|
||||
class EventType(models.Model):
|
||||
_name = 'event.type'
|
||||
_inherit = ['event.type']
|
||||
|
||||
def _default_question_ids(self):
|
||||
return [
|
||||
(0, 0, {'title': _('Name'), 'question_type': 'name', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': _('Email'), 'question_type': 'email', 'is_mandatory_answer': True}),
|
||||
(0, 0, {'title': _('Phone'), 'question_type': 'phone'}),
|
||||
]
|
||||
|
||||
website_menu = fields.Boolean('Display a dedicated menu on Website')
|
||||
community_menu = fields.Boolean(
|
||||
"Community Menu", compute="_compute_community_menu",
|
||||
@@ -17,7 +24,7 @@ class EventType(models.Model):
|
||||
'Extra Register Button', compute='_compute_menu_register_cta',
|
||||
readonly=False, store=True)
|
||||
question_ids = fields.One2many(
|
||||
'event.question', 'event_type_id',
|
||||
'event.question', 'event_type_id', default=_default_question_ids,
|
||||
string='Questions', copy=True)
|
||||
|
||||
@api.depends('website_menu')
|
||||
|
||||
@@ -25,10 +25,10 @@ registry.category("web_tour.tours").add('test_tickets_questions', {
|
||||
trigger: 'div:contains("Ticket #1").modal-body input[name*="phone"]',
|
||||
run: 'text +32499123456'
|
||||
}, {
|
||||
trigger: 'div:contains("Ticket #1").modal-body select[name*="question_answer"]',
|
||||
trigger: 'div:contains("Ticket #1").modal-body select[name*="1-simple_choice"]',
|
||||
run: 'text Vegetarian'
|
||||
}, {
|
||||
trigger: 'div:contains("Ticket #1").modal-body textarea[name*="question_answer"]',
|
||||
trigger: 'div:contains("Ticket #1").modal-body textarea[name*="1-text_box"]',
|
||||
run: 'text Fish and Nuts'
|
||||
}, {
|
||||
trigger: 'div:contains("Ticket #2").modal-body input[name*="name"]',
|
||||
@@ -37,13 +37,16 @@ registry.category("web_tour.tours").add('test_tickets_questions', {
|
||||
trigger: 'div:contains("Ticket #2").modal-body input[name*="email"]',
|
||||
run: 'text attendee-b@gmail.com'
|
||||
}, {
|
||||
trigger: 'div:contains("Ticket #2").modal-body select[name*="question_answer"]',
|
||||
trigger: 'div:contains("Ticket #2").modal-body input[name*="company_name"]',
|
||||
run: 'text My Company'
|
||||
}, {
|
||||
trigger: 'div:contains("Ticket #2").modal-body select[name*="2-simple_choice"]',
|
||||
run: 'text Pastafarian'
|
||||
}, {
|
||||
trigger: 'div.o_wevent_registration_question_global select[name*="question_answer"]',
|
||||
trigger: 'div.o_wevent_registration_question_global select[name*="0-simple_choice"]',
|
||||
run: 'text A friend'
|
||||
}, {
|
||||
trigger: 'button:contains("Continue")',
|
||||
trigger: 'button[type=submit]',
|
||||
run: 'click'
|
||||
}, {
|
||||
// The tour stops too early and the registration fails if we don't wait the confirmation.
|
||||
|
||||
@@ -2,12 +2,9 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import datetime, timedelta, time
|
||||
from unittest.mock import patch
|
||||
|
||||
from odoo.addons.event.tests.common import EventCase
|
||||
from odoo.addons.mail.tests.common import mail_new_test_user
|
||||
from odoo.fields import Datetime as FieldsDatetime, Date as FieldsDate
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class OnlineEventCase(EventCase):
|
||||
|
||||
@@ -25,10 +25,15 @@ class TestEventData(TestEventQuestionCommon):
|
||||
|
||||
self.assertEqual(
|
||||
event.question_ids.mapped('question_type'),
|
||||
['simple_choice', 'simple_choice', 'text_box'])
|
||||
self.assertEqual(event.specific_question_ids.title, 'Question1')
|
||||
['name', 'email', 'phone', 'simple_choice', 'simple_choice', 'text_box'])
|
||||
self.assertEqual(event.specific_question_ids.filtered(
|
||||
lambda q: q.question_type in ['simple_choice', 'text_box']).title, 'Question1')
|
||||
self.assertEqual(event.specific_question_ids.filtered(
|
||||
lambda q: q.question_type in ['name', 'email', 'phone', 'company_name'])
|
||||
.mapped('title'), ['Name', 'Email', 'Phone'])
|
||||
self.assertEqual(
|
||||
set(event.specific_question_ids.mapped('answer_ids.name')),
|
||||
set(event.specific_question_ids.filtered(
|
||||
lambda q: q.question_type in ['simple_choice', 'text_box']).mapped('answer_ids.name')),
|
||||
set(['Q1-Answer1', 'Q1-Answer2']))
|
||||
self.assertEqual(len(event.general_question_ids), 2)
|
||||
self.assertEqual(event.general_question_ids[0].title, 'Question2')
|
||||
@@ -55,19 +60,34 @@ class TestEventData(TestEventQuestionCommon):
|
||||
'seats_max': 200,
|
||||
}])
|
||||
|
||||
[name_question, email_question, phone_question] = event.question_ids.filtered(
|
||||
lambda q: q.question_type in ('name', 'email', 'phone', 'company_name'))
|
||||
|
||||
[second_phone_question, company_name_question] = self.env['event.question'].create([{
|
||||
'title': 'Second Phone',
|
||||
'question_type': 'phone',
|
||||
'event_id': event.id,
|
||||
}, {
|
||||
'title': 'Company Name',
|
||||
'question_type': 'company_name',
|
||||
'event_id': event.id,
|
||||
}])
|
||||
|
||||
form_details = {
|
||||
'1-name': 'Pixis',
|
||||
'1-email': 'pixis@gmail.com',
|
||||
'1-phone': '+32444444444',
|
||||
'1-name-%s' % name_question.id: 'Pixis',
|
||||
'1-email-%s' % email_question.id: 'pixis@gmail.com',
|
||||
'1-phone-%s' % phone_question.id: '+32444444444',
|
||||
'1-phone-%s' % second_phone_question.id: '+32555555555',
|
||||
'1-event_ticket_id': ticket_id_1.id,
|
||||
'2-name': 'Geluchat',
|
||||
'2-email': 'geluchat@gmail.com',
|
||||
'2-phone': '+32777777777',
|
||||
'2-name-%s' % name_question.id: 'Geluchat',
|
||||
'2-email-%s' % email_question.id: 'geluchat@gmail.com',
|
||||
'2-phone-%s' % phone_question.id: '+32777777777',
|
||||
'2-company_name-%s' % company_name_question.id: 'My Company',
|
||||
'2-event_ticket_id': ticket_id_2.id,
|
||||
'question_answer-1-%s' % self.event_question_1.id: '5',
|
||||
'question_answer-2-%s' % self.event_question_1.id: '9',
|
||||
'question_answer-0-%s' % self.event_question_2.id: '7',
|
||||
'question_answer-0-%s' % self.event_question_3.id: 'Free Text',
|
||||
'1-simple_choice-%s' % self.event_question_1.id: '5',
|
||||
'2-simple_choice-%s' % self.event_question_1.id: '9',
|
||||
'0-simple_choice-%s' % self.event_question_2.id: '7',
|
||||
'0-text_box-%s' % self.event_question_3.id: 'Free Text',
|
||||
}
|
||||
|
||||
with MockRequest(self.env):
|
||||
@@ -76,11 +96,20 @@ class TestEventData(TestEventQuestionCommon):
|
||||
self.assertEqual(registrations, [
|
||||
{'name': 'Pixis', 'email': 'pixis@gmail.com', 'phone': '+32444444444', 'event_ticket_id': ticket_id_1.id,
|
||||
'registration_answer_ids': [
|
||||
(0, 0, {'question_id': name_question.id, 'value_text_box': 'Pixis'}),
|
||||
(0, 0, {'question_id': email_question.id, 'value_text_box': 'pixis@gmail.com'}),
|
||||
(0, 0, {'question_id': phone_question.id, 'value_text_box': '+32444444444'}),
|
||||
(0, 0, {'question_id': second_phone_question.id, 'value_text_box': '+32555555555'}),
|
||||
(0, 0, {'question_id': self.event_question_1.id, 'value_answer_id': 5}),
|
||||
(0, 0, {'question_id': self.event_question_2.id, 'value_answer_id': 7}),
|
||||
(0, 0, {'question_id': self.event_question_3.id, 'value_text_box': 'Free Text'})]},
|
||||
{'name': 'Geluchat', 'email': 'geluchat@gmail.com', 'phone': '+32777777777', 'event_ticket_id': ticket_id_2.id,
|
||||
{'name': 'Geluchat', 'email': 'geluchat@gmail.com', 'phone': '+32777777777', 'company_name': 'My Company',
|
||||
'event_ticket_id': ticket_id_2.id,
|
||||
'registration_answer_ids': [
|
||||
(0, 0, {'question_id': name_question.id, 'value_text_box': 'Geluchat'}),
|
||||
(0, 0, {'question_id': email_question.id, 'value_text_box': 'geluchat@gmail.com'}),
|
||||
(0, 0, {'question_id': phone_question.id, 'value_text_box': '+32777777777'}),
|
||||
(0, 0, {'question_id': company_name_question.id, 'value_text_box': 'My Company'}),
|
||||
(0, 0, {'question_id': self.event_question_1.id, 'value_answer_id': 9}),
|
||||
(0, 0, {'question_id': self.event_question_2.id, 'value_answer_id': 7}),
|
||||
(0, 0, {'question_id': self.event_question_3.id, 'value_text_box': 'Free Text'})]}
|
||||
|
||||
@@ -48,6 +48,18 @@ class TestUi(HttpCaseWithUserDemo):
|
||||
})],
|
||||
'website_published': True,
|
||||
'question_ids': [(0, 0, {
|
||||
'title': 'Name',
|
||||
'question_type': 'name',
|
||||
}), (0, 0, {
|
||||
'title': 'Email',
|
||||
'question_type': 'email',
|
||||
}), (0, 0, {
|
||||
'title': 'Phone',
|
||||
'question_type': 'phone',
|
||||
}), (0, 0, {
|
||||
'title': 'Company Name',
|
||||
'question_type': 'company_name',
|
||||
}), (0, 0, {
|
||||
'title': 'Meal Type',
|
||||
'question_type': 'simple_choice',
|
||||
'answer_ids': [
|
||||
@@ -81,12 +93,13 @@ class TestUi(HttpCaseWithUserDemo):
|
||||
self.assertEqual(first_registration.name, 'Attendee A')
|
||||
self.assertEqual(first_registration.phone, '+32499123456')
|
||||
self.assertEqual(second_registration.name, 'Attendee B')
|
||||
self.assertEqual(second_registration.company_name, 'My Company')
|
||||
|
||||
event_questions = registrations.mapped('event_id.question_ids')
|
||||
self.assertEqual(len(event_questions), 3)
|
||||
self.assertEqual(len(event_questions), 7)
|
||||
|
||||
first_registration_answers = first_registration.registration_answer_ids
|
||||
self.assertEqual(len(first_registration_answers), 3)
|
||||
self.assertEqual(len(first_registration_answers), 6)
|
||||
|
||||
self.assertEqual(first_registration_answers.filtered(
|
||||
lambda answer: answer.question_id.title == 'Meal Type'
|
||||
@@ -101,7 +114,7 @@ class TestUi(HttpCaseWithUserDemo):
|
||||
).value_answer_id.name, 'A friend')
|
||||
|
||||
second_registration_answers = second_registration.registration_answer_ids
|
||||
self.assertEqual(len(second_registration_answers), 2)
|
||||
self.assertEqual(len(second_registration_answers), 5)
|
||||
|
||||
self.assertEqual(second_registration_answers.filtered(
|
||||
lambda answer: answer.question_id.title == 'Meal Type'
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
<field name="question_type" string="Type" />
|
||||
<field name="answer_ids" widget="many2many_tags"
|
||||
attrs="{'invisible': [('question_type', '!=', 'simple_choice')]}" />
|
||||
<button name="action_view_question_answers" type="object" class="p-0" icon="fa-bar-chart pe-1" string="Stats" title="Answer Breakdown"/>
|
||||
<button name="action_view_question_answers" type="object" class="p-0" icon="fa-bar-chart pe-1" string="Stats"
|
||||
title="Answer Breakdown" attrs="{'invisible': [('question_type', 'not in', ['simple_choice', 'text_box'])]}"/>
|
||||
</tree>
|
||||
<!-- Need to repeat the whole tree form here to be able to create answers properly
|
||||
Without this, the sub-fields of answer_ids are unknown to the web framework.
|
||||
@@ -50,7 +51,7 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="is_mandatory_answer"/>
|
||||
<field name="question_type" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="question_type" widget="radio"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="once_per_order"/>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="is_mandatory_answer"/>
|
||||
<field name="question_type" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="question_type" widget="radio"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="once_per_order"/>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<field name="value_answer_id"
|
||||
attrs="{'invisible': [('question_type', '!=', 'simple_choice')]}"
|
||||
domain="[('question_id', '=', question_id)]" options="{'no_create': True}"/>
|
||||
<field name="value_text_box" attrs="{'invisible': [('question_type', '!=', 'text_box')]}" />
|
||||
<field name="value_text_box" attrs="{'invisible': [('question_type', '=', 'simple_choice')]}" />
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
@@ -281,65 +281,47 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header align-items-center">
|
||||
<h4 class="modal-title">Attendees</h4>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"/>
|
||||
</div>
|
||||
<t t-set="counter_type" t-value="1"/>
|
||||
<t t-set="counter" t-value="0"/>
|
||||
<t t-foreach="tickets" t-as="ticket" t-if="availability_check">
|
||||
<t t-set="input_type_by_question_type" t-value="{'name': 'text', 'email': 'email', 'phone': 'tel', 'company_name': 'text'}"/>
|
||||
<t t-if="availability_check" t-foreach="tickets" t-as="ticket">
|
||||
<t t-foreach="range(1, ticket['quantity'] + 1)" t-as="att_counter" name="attendee_loop">
|
||||
<t t-set="counter" t-value="counter + 1"/>
|
||||
<div class="modal-body border-bottom">
|
||||
<h5 class="mt-1 pb-2 border-bottom">Ticket #<span t-out="counter"/> <small class="text-muted">- <span t-out="ticket['name']"/></small></h5>
|
||||
<div class="row">
|
||||
<div class="col-lg my-2">
|
||||
<label>Name *</label>
|
||||
<input class="form-control" type="text" t-attf-name="#{counter}-name" required="This field is required"
|
||||
t-att-value="default_first_attendee.get('name', '') if counter == 1 else ''"/>
|
||||
</div>
|
||||
<div class="col-lg my-2">
|
||||
<label>Email *</label>
|
||||
<input class="form-control" type="email" t-attf-name="#{counter}-email" required="This field is required"
|
||||
t-att-value="default_first_attendee.get('email', '') if counter == 1 else ''"/>
|
||||
</div>
|
||||
<div class="col-lg my-2">
|
||||
<label>Phone <small>(Optional)</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>
|
||||
<t t-if="event.specific_question_ids">
|
||||
<div t-foreach="event.specific_question_ids" t-as="question" class="row" t-att-name="question.title">
|
||||
<div class="col-lg-6 mt-2">
|
||||
<div class="modal-body">
|
||||
<h5 t-attf-class="mt-1 pb-2 #{'border-bottom' if event.question_ids else ''}">Ticket #<span t-out="counter"/> <small class="text-muted">- <span t-out="ticket['name']"/></small></h5>
|
||||
<div t-if="event.specific_question_ids" class="row">
|
||||
<t t-foreach="event.specific_question_ids" t-as="question">
|
||||
<div class="col-lg-12 mt-2">
|
||||
<t t-call="website_event.registration_event_question">
|
||||
<t t-set="registration_index" t-value="counter"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
<input class="d-none" type="text" t-attf-name="#{counter}-event_ticket_id" t-attf-value="#{ticket['id']}"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-set="counter_type" t-value="counter_type + 1"/>
|
||||
</t>
|
||||
<t t-if="not availability_check">
|
||||
<div class="modal-body border-bottom">
|
||||
<strong> You ordered more tickets than available seats</strong>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="event.general_question_ids">
|
||||
<div class="modal-body border-bottom o_wevent_registration_question_global">
|
||||
<div t-foreach="event.general_question_ids" t-as="question" class="row" t-att-name="question.title">
|
||||
<div class="col-lg-6 mt-2">
|
||||
<div t-if="availability_check and event.general_question_ids" class="modal-body border-top o_wevent_registration_question_global">
|
||||
<div class="row">
|
||||
<t t-foreach="event.general_question_ids" t-as="question">
|
||||
<div class="col-lg-12 mt-2">
|
||||
<t t-call="website_event.registration_event_question">
|
||||
<t t-set="registration_index" t-value="0"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<t t-elif="not availability_check">
|
||||
<div class="modal-body border-bottom">
|
||||
<strong> You ordered more tickets than available seats</strong>
|
||||
</div>
|
||||
</t>
|
||||
<div class="modal-footer border-0 justify-content-between">
|
||||
<div class="modal-footer border-top justify-content-between">
|
||||
<button type="button" class="btn btn-secondary js_goto_event" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary" t-if="availability_check">Continue</button>
|
||||
<button type="submit" class="btn btn-primary" t-if="availability_check">Confirm Registration</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -350,18 +332,23 @@
|
||||
<template id="registration_event_question" name="Registration Event Question">
|
||||
<label t-out="question.title"/>
|
||||
<span t-if="question.is_mandatory_answer">*</span>
|
||||
<t t-if="question.question_type == 'simple_choice'">
|
||||
<select t-attf-name="question_answer-#{registration_index}-#{question.id}" class="form-select"
|
||||
t-att-required="question.is_mandatory_answer">
|
||||
<t t-if="question.question_type in ['name', 'email', 'phone', 'company_name']">
|
||||
<input class="form-control" t-att-type="input_type_by_question_type[question.question_type]"
|
||||
t-attf-name="#{registration_index}-#{question.question_type}-#{question.id}"
|
||||
t-att-required="question.is_mandatory_answer" t-att-value="default_first_attendee.get(question.question_type, '') if counter in (0,1) else ''"/>
|
||||
</t>
|
||||
<t t-elif="question.question_type == 'simple_choice'">
|
||||
<select t-attf-name="#{registration_index}-#{question.question_type}-#{question.id}"
|
||||
class="form-select" t-att-required="question.is_mandatory_answer">
|
||||
<option value=""/>
|
||||
<t t-foreach="question.answer_ids" t-as="answer">
|
||||
<option t-out="answer.name" t-att-value="answer.id"/>
|
||||
</t>
|
||||
</select>
|
||||
</t>
|
||||
<t t-elif="question.question_type == 'text_box'">
|
||||
<textarea t-attf-name="question_answer-#{registration_index}-#{question.id}" class="col-lg-12 form-control"
|
||||
t-att-required="question.is_mandatory_answer"/>
|
||||
<t t-else="">
|
||||
<textarea t-attf-name="#{registration_index}-#{question.question_type}-#{question.id}"
|
||||
class="col-lg-12 form-control" t-att-required="question.is_mandatory_answer"/>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
@@ -377,21 +364,19 @@
|
||||
<div class="row mb-3 o_wereg_confirmed_attendees">
|
||||
<div class="col-md-4 col-xs-12 mt-3" t-foreach="attendees" t-as="attendee">
|
||||
<div class="d-flex flex-column">
|
||||
<span class="fw-bold text-truncate">
|
||||
<t t-if="attendee.name" t-out="attendee.name"/>
|
||||
<t t-else="">N/A</t>
|
||||
<span t-if="attendee.name" class="fw-bold text-truncate">
|
||||
<t t-out="attendee.name"/>
|
||||
</span>
|
||||
<span class="text-truncate">
|
||||
<i class="fa fa-envelope me-2 "></i>
|
||||
<t t-if="attendee.email" t-out="attendee.email"/>
|
||||
<t t-else="">N/A</t>
|
||||
<span t-if="attendee.email" class="text-truncate">
|
||||
<i class="fa fa-envelope me-2"/>
|
||||
<t t-out="attendee.email"/>
|
||||
</span>
|
||||
<span t-if="attendee.phone">
|
||||
<i class="fa fa-phone me-2"></i>
|
||||
<i class="fa fa-phone me-2"/>
|
||||
<t t-out="attendee.phone"/>
|
||||
</span>
|
||||
<span>
|
||||
<i class="fa fa-ticket me-2"></i>
|
||||
<i class="fa fa-ticket me-2"/>
|
||||
<t t-if="attendee.event_ticket_id">
|
||||
<t t-out="attendee.event_ticket_id.name"/> (Ref: <t t-out="attendee.id"/>)
|
||||
</t>
|
||||
|
||||
@@ -29,23 +29,23 @@ registry.category("web_tour.tours").add('event_buy_tickets', {
|
||||
},
|
||||
{
|
||||
content: "Fill attendees details",
|
||||
trigger: 'form[id="attendee_registration"] .btn:contains("Continue")',
|
||||
trigger: 'form[id="attendee_registration"] .btn[type=submit]',
|
||||
run: function () {
|
||||
$("input[name='1-name']").val("Att1");
|
||||
$("input[name='1-phone']").val("111 111");
|
||||
$("input[name='1-email']").val("att1@example.com");
|
||||
$("input[name='2-name']").val("Att2");
|
||||
$("input[name='2-phone']").val("222 222");
|
||||
$("input[name='2-email']").val("att2@example.com");
|
||||
$("input[name='3-name']").val("Att3");
|
||||
$("input[name='3-phone']").val("333 333");
|
||||
$("input[name='3-email']").val("att3@example.com");
|
||||
$("input[name*='1-name']").val("Att1");
|
||||
$("input[name*='1-phone']").val("111 111");
|
||||
$("input[name*='1-email']").val("att1@example.com");
|
||||
$("input[name*='2-name']").val("Att2");
|
||||
$("input[name*='2-phone']").val("222 222");
|
||||
$("input[name*='2-email']").val("att2@example.com");
|
||||
$("input[name*='3-name']").val("Att3");
|
||||
$("input[name*='3-phone']").val("333 333");
|
||||
$("input[name*='3-email']").val("att3@example.com");
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "Validate attendees details",
|
||||
extra_trigger: "input[name='1-name'], input[name='2-name'], input[name='3-name']",
|
||||
trigger: 'button:contains("Continue")',
|
||||
extra_trigger: "input[name*='1-name'], input[name*='2-name'], input[name*='3-name']",
|
||||
trigger: 'button[type=submit]',
|
||||
},
|
||||
{
|
||||
content: "Check that the cart contains exactly 3 triggers",
|
||||
|
||||
@@ -26,20 +26,20 @@ registry.category("web_tour.tours").add('event_buy_last_ticket', {
|
||||
},
|
||||
{
|
||||
content: "Fill attendees details",
|
||||
trigger: 'form[id="attendee_registration"] .btn:contains("Continue")',
|
||||
trigger: 'form[id="attendee_registration"] .btn[type=submit]',
|
||||
run: function () {
|
||||
$("input[name='1-name']").val("Att1");
|
||||
$("input[name='1-phone']").val("111 111");
|
||||
$("input[name='1-email']").val("att1@example.com");
|
||||
$("input[name='2-name']").val("Att2");
|
||||
$("input[name='2-phone']").val("222 222");
|
||||
$("input[name='2-email']").val("att2@example.com");
|
||||
$("input[name*='1-name']").val("Att1");
|
||||
$("input[name*='1-phone']").val("111 111");
|
||||
$("input[name*='1-email']").val("att1@example.com");
|
||||
$("input[name*='2-name']").val("Att2");
|
||||
$("input[name*='2-phone']").val("222 222");
|
||||
$("input[name*='2-email']").val("att2@example.com");
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "Validate attendees details",
|
||||
extra_trigger: "input[name='1-name'], input[name='2-name']",
|
||||
trigger: 'button:contains("Continue")',
|
||||
extra_trigger: "input[name*='1-name'], input[name*='2-name']",
|
||||
trigger: 'button[type=submit]',
|
||||
},
|
||||
{
|
||||
content: "Fill address",
|
||||
|
||||
@@ -18,17 +18,17 @@
|
||||
},
|
||||
{
|
||||
content: "Fill attendees details",
|
||||
trigger: 'form[id="attendee_registration"] .btn:contains("Continue")',
|
||||
trigger: 'form[id="attendee_registration"] .btn[type=submit]',
|
||||
run: function () {
|
||||
$("input[name='1-name']").val("Great Name");
|
||||
$("input[name='1-phone']").val("111 111");
|
||||
$("input[name='1-email']").val("great@name.com");
|
||||
$("input[name*='1-name']").val("Great Name");
|
||||
$("input[name*='1-phone']").val("111 111");
|
||||
$("input[name*='1-email']").val("great@name.com");
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "Validate attendees details",
|
||||
extra_trigger: "input[name='1-name'], input[name='2-name']",
|
||||
trigger: 'button:contains("Continue")',
|
||||
extra_trigger: "input[name*='1-name'], input[name*='2-name']",
|
||||
trigger: 'button[type=submit]',
|
||||
},
|
||||
...getPriceListChecksSteps({
|
||||
pricelistName: "EUR With Discount Included",
|
||||
|
||||
@@ -88,7 +88,13 @@
|
||||
<span class="fa fa-sign-in"/>
|
||||
</a>
|
||||
</t>
|
||||
<t t-else="">$0</t>
|
||||
<t t-else="">
|
||||
<t t-set="has_paying_ticket" t-value="any(ticket.get('price', 0) > 0 for ticket in tickets)"/>
|
||||
<button t-if="availability_check" type="submit" class="btn btn-primary">
|
||||
<span t-if="has_paying_ticket">Go to Payment</span>
|
||||
<span t-else="">Confirm Registration</span>
|
||||
</button>
|
||||
</t>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user