summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Mathot <rim@odoo.com>2015-02-17 15:00:35 +0100
committerRichard Mathot <rim@odoo.com>2015-02-19 11:22:59 +0100
commit194d95cd475b7e34ba7057ebdfc682624adac07f (patch)
tree8f94effc5f3a4adb643059e2d4295a8b4fbdba4b
parent2334917ed38f4f1c4ae832dfef331aad8995847e (diff)
[ADD] website_event_questions: ask questions to event attendees
[IMP] event,event_sale,website_event_sale: refactoring to be more easily extended (code portions are courtesy of Thibault Delavallée <tde@odoo.com>)
-rw-r--r--addons/event/event.py18
-rw-r--r--addons/event/event_demo.xml10
-rw-r--r--addons/event/event_view.xml2
-rw-r--r--addons/event_sale/models/event.py18
-rw-r--r--addons/event_sale/models/sale_order.py17
-rw-r--r--addons/event_sale/views/event.xml2
-rw-r--r--addons/website_event/controllers/main.py23
-rw-r--r--addons/website_event/views/website_event.xml35
-rw-r--r--addons/website_event_questions/__init__.py24
-rw-r--r--addons/website_event_questions/__openerp__.py20
-rw-r--r--addons/website_event_questions/controllers/__init__.py3
-rw-r--r--addons/website_event_questions/controllers/main.py17
-rw-r--r--addons/website_event_questions/data/demo.xml71
-rw-r--r--addons/website_event_questions/models/__init__.py3
-rw-r--r--addons/website_event_questions/models/event.py57
-rw-r--r--addons/website_event_questions/report/__init__.py3
-rw-r--r--addons/website_event_questions/report/report_event_question_view.xml61
-rw-r--r--addons/website_event_questions/report/report_event_registrations_questions.py37
-rw-r--r--addons/website_event_questions/security/ir.model.access.csv7
-rw-r--r--addons/website_event_questions/views/website_event_questions_backend.xml78
-rw-r--r--addons/website_event_questions/views/website_event_questions_templates.xml46
21 files changed, 508 insertions, 44 deletions
diff --git a/addons/event/event.py b/addons/event/event.py
index 8efd1eb2942..89a275d54d1 100644
--- a/addons/event/event.py
+++ b/addons/event/event.py
@@ -303,6 +303,24 @@ class event_registration(models.Model):
registration.sudo().confirm_registration()
return registration
+ @api.model
+ def _prepare_attendee_values(self, registration):
+ """ Method preparing the values to create new attendees based on a
+ sale order line. It takes some registration data (dict-based) that are
+ optional values coming from an external input like a web page. This method
+ is meant to be inherited in various addons that sell events. """
+ partner_id = registration.pop('partner_id', self.env.user.partner_id)
+ event_id = registration.pop('event_id', False)
+ data = {
+ 'name': registration.get('name', partner_id.name),
+ 'phone': registration.get('phone', partner_id.phone),
+ 'email': registration.get('email', partner_id.email),
+ 'partner_id': partner_id.id,
+ 'event_id': event_id and event_id.id or False,
+ }
+ data.update({key: registration[key] for key in registration.keys() if key in self._fields})
+ return data
+
@api.one
def do_draft(self):
self.state = 'draft'
diff --git a/addons/event/event_demo.xml b/addons/event/event_demo.xml
index 8e2bccf0d08..fd48b63de91 100644
--- a/addons/event/event_demo.xml
+++ b/addons/event/event_demo.xml
@@ -227,7 +227,15 @@
<field name="event_id" ref="event_1"/>
</record>
- <record id="reg_0_2" model="event.registration">
+ <record id="reg_1_3" model="event.registration">
+ <field name="name">Delta PC</field>
+ <field name="email">deltapc@yourcompany.example.com</field>
+ <field name="phone">+1 510 340 2385</field>
+ <field name="partner_id" ref="base.res_partner_4"/>
+ <field name="event_id" ref="event_1"/>
+ </record>
+
+ <record id="reg_2_0" model="event.registration">
<field name="name">Camptocamp</field>
<field name="email">openerp@camptocamp.com</field>
<field name="phone">+41 21 619 10 04 </field>
diff --git a/addons/event/event_view.xml b/addons/event/event_view.xml
index f850b2eb84f..daa01358b6b 100644
--- a/addons/event/event_view.xml
+++ b/addons/event/event_view.xml
@@ -305,7 +305,7 @@
</header>
<sheet string="Registration">
<group>
- <group string="Attendee Information" name="attendee">
+ <group string="Attendee" name="attendee">
<field name="name"/>
<field name="phone"/>
<field name="email"/>
diff --git a/addons/event_sale/models/event.py b/addons/event_sale/models/event.py
index cb676c6d224..b1b81db9d60 100644
--- a/addons/event_sale/models/event.py
+++ b/addons/event_sale/models/event.py
@@ -175,3 +175,21 @@ class event_registration(models.Model):
'order': res.origin or res.sale_order_id.name})
res.message_post(body=message)
return res
+
+ @api.model
+ def _prepare_attendee_values(self, registration):
+ """ Override to add sale related stuff """
+ line_id = registration.get('sale_order_line_id')
+ if line_id:
+ registration.setdefault('partner_id', line_id.order_id.partner_id)
+ att_data = super(event_registration, self)._prepare_attendee_values(registration)
+ if line_id:
+ att_data.update({
+ 'event_id': line_id.event_id.id,
+ 'event_id': line_id.event_id.id,
+ 'event_ticket_id': line_id.event_ticket_id.id,
+ 'origin': line_id.order_id.name,
+ 'sale_order_id': line_id.order_id.id,
+ 'sale_order_line_id': line_id.id,
+ })
+ return att_data
diff --git a/addons/event_sale/models/sale_order.py b/addons/event_sale/models/sale_order.py
index ba05138ae74..25f9e473f32 100644
--- a/addons/event_sale/models/sale_order.py
+++ b/addons/event_sale/models/sale_order.py
@@ -62,7 +62,8 @@ class sale_order_line(osv.osv):
order line has a product_uom_qty attribute that will be the number of
registrations linked to this line. This method update existing registrations
and create new one for missing one. """
- registrations = self.env['event.registration'].search([('sale_order_line_id', 'in', self.ids)])
+ Registration = self.env['event.registration']
+ registrations = Registration.search([('sale_order_line_id', 'in', self.ids)])
for so_line in [l for l in self if l.event_id]:
existing_registrations = registrations.filtered(lambda self: self.sale_order_line_id.id == so_line.id)
if confirm:
@@ -75,17 +76,9 @@ class sale_order_line(osv.osv):
if registration_data:
registration = registration_data.pop()
# TDE CHECK: auto confirmation
- self.env['event.registration'].with_context(registration_force_draft=True).create({
- 'name': registration.get('name', so_line.order_id.partner_id.name),
- 'phone': registration.get('phone', so_line.order_id.partner_id.phone),
- 'email': registration.get('email', so_line.order_id.partner_id.email),
- 'event_id': so_line.event_id.id,
- 'event_ticket_id': so_line.event_ticket_id.id,
- 'partner_id': so_line.order_id.partner_id.id,
- 'origin': so_line.order_id.name,
- 'sale_order_id': so_line.order_id.id,
- 'sale_order_line_id': so_line.id,
- })
+ registration['sale_order_line_id'] = so_line
+ self.env['event.registration'].with_context(registration_force_draft=True).create(
+ Registration._prepare_attendee_values(registration))
return True
def button_confirm(self, cr, uid, ids, context=None):
diff --git a/addons/event_sale/views/event.xml b/addons/event_sale/views/event.xml
index 0d540463d49..91705c5684d 100644
--- a/addons/event_sale/views/event.xml
+++ b/addons/event_sale/views/event.xml
@@ -35,8 +35,8 @@
</field>
<group name="event" position="after">
<group string="Origin">
- <field name="origin" attrs="{'invisible': [('sale_order_id', '!=', False)]}"/>
<field name="sale_order_id"/>
+ <field name="origin" attrs="{'invisible': [('sale_order_id', '!=', False)]}"/>
<field name="sale_order_line_id" readonly="1" attrs="{'invisible': [('sale_order_id', '=', False)]}"/>
</group>
</group>
diff --git a/addons/website_event/controllers/main.py b/addons/website_event/controllers/main.py
index 134371a3caf..d9ec06e4e88 100644
--- a/addons/website_event/controllers/main.py
+++ b/addons/website_event/controllers/main.py
@@ -4,7 +4,6 @@ import time
import werkzeug.urls
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
-from collections import OrderedDict
from openerp import http
from openerp import tools, SUPERUSER_ID
@@ -244,9 +243,16 @@ class website_event(http.Controller):
def _process_registration_details(self, details):
''' Process data posted from the attendee details form. '''
registrations = {}
+ global_values = {}
for key, value in details.iteritems():
counter, field_name = key.split('-', 1)
- registrations.setdefault(counter, dict())[field_name] = value
+ if counter == '0':
+ global_values[field_name] = value
+ else:
+ registrations.setdefault(counter, dict())[field_name] = value
+ for key, value in global_values.iteritems():
+ for registration in registrations.values():
+ registration[key] = value
return registrations.values()
@http.route(['/event/<model("event.event"):event>/registration/confirm'], type='http', auth="public", methods=['POST'], website=True)
@@ -256,16 +262,13 @@ class website_event(http.Controller):
registrations = self._process_registration_details(post)
registration_ids = []
- user = request.registry.get('res.users').browse(cr, uid, uid, context=context)
for registration in registrations:
+ registration['event_id'] = event
registration_ids.append(
- Registration.create(cr, SUPERUSER_ID, {
- 'name': registration.get('name', user.name),
- 'phone': registration.get('phone', user.phone),
- 'email': registration.get('email', user.email),
- 'partner_id': user.partner_id.id,
- 'event_id': event.id,
- }, context=context))
+ Registration.create(
+ cr, SUPERUSER_ID,
+ Registration._prepare_attendee_values(cr, SUPERUSER_ID, registration),
+ context=context))
attendees = Registration.browse(cr, uid, registration_ids, context=context)
return request.website.render("website_event.registration_complete", {
diff --git a/addons/website_event/views/website_event.xml b/addons/website_event/views/website_event.xml
index a0eda0a6e60..e682e37c63b 100644
--- a/addons/website_event/views/website_event.xml
+++ b/addons/website_event/views/website_event.xml
@@ -428,31 +428,28 @@
<t t-set="counter_type" t-value="1"/>
<t t-set="counter" t-value="0"/>
<t t-foreach="tickets" t-as="ticket">
- <div>
- <h4>
- <strong>
- Ticket Type #<t t-raw="counter_type"/>: <t t-esc="ticket['name']"/> (
- <t t-if="ticket['price'] > 0">
- <t t-esc="ticket['price']"/>
- <t t-esc="website.pricelist_id.currency_id.symbol"/>
- </t>
- <t t-if="ticket['price'] == 0">Free</t>)
- </strong>
- </h4><hr/>
- </div>
+ <h4 class="page-header mt16">
+ <strong>
+ Ticket Type #<t t-raw="counter_type"/>: <t t-esc="ticket['name']"/> (
+ <t t-if="ticket['price'] > 0">
+ <t t-esc="ticket['price']"/>
+ <t t-esc="website.pricelist_id.currency_id.symbol"/>
+ </t>
+ <t t-if="ticket['price'] == 0">Free</t>)
+ </strong>
+ </h4>
<div class="row">
<div class="col-md-4"><strong>Name</strong></div>
<div class="col-md-3"><strong>Phone</strong> <span class="text-muted">(Optional)</span></div>
<div class="col-md-5"><strong>Email</strong> <span class="text-muted">(Optional)</span></div>
</div>
- <t t-foreach="range(1, ticket['quantity'] + 1)" t-as="att_counter">
+ <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="row">
- <div class="col-md-4"><input class='form-control input-sm' type='text' t-attf-name="#{counter}-name" required="This field is required" t-att-placeholder="'Attendee #%s' %counter"/></div>
- <div class="col-md-3"><input class='form-control input-sm' type='tel' t-attf-name="#{counter}-phone"/></div>
- <div class="col-md-5"><input class='form-control input-sm' type='email' t-attf-name="#{counter}-email"/></div>
+ <div class="row mb4">
+ <div class="col-md-4"><input class='form-control' type='text' t-attf-name="#{counter}-name" required="This field is required" t-att-placeholder="'Attendee #%s' %counter"/></div>
+ <div class="col-md-3"><input class='form-control' type='tel' t-attf-name="#{counter}-phone"/></div>
+ <div class="col-md-5"><input class='form-control' type='email' t-attf-name="#{counter}-email"/></div>
<input class='hidden' type='text' t-attf-name="#{counter}-ticket_id" t-attf-value="#{ticket['id']}"/>
- <hr style="width:50%"/>
</div>
</t>
<t t-set="counter_type" t-value="counter_type + 1"/>
@@ -461,7 +458,7 @@
</div>
<div class="modal-footer">
<div class="pull-left">
- <button type="submit" class="btn btn-primary">Continue</button> or
+ <button type="submit" class="btn btn-primary">Continue</button> or
<a class="js_goto_event"> Cancel Registration</a>
</div>
</div>
diff --git a/addons/website_event_questions/__init__.py b/addons/website_event_questions/__init__.py
new file mode 100644
index 00000000000..455ae859a94
--- /dev/null
+++ b/addons/website_event_questions/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2015-TODAY Odoo S.A. (<https://www.odoo.com>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import controllers
+import models
+import report
diff --git a/addons/website_event_questions/__openerp__.py b/addons/website_event_questions/__openerp__.py
new file mode 100644
index 00000000000..24025e15b62
--- /dev/null
+++ b/addons/website_event_questions/__openerp__.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+
+{
+ 'name': 'Questions on Events',
+ 'description': 'Questions on Events',
+ 'category': 'Website',
+ 'version': '1.0',
+ 'author': 'Odoo S.A.',
+ 'depends': ['website_event'],
+ 'data': [
+ 'views/website_event_questions_backend.xml',
+ 'views/website_event_questions_templates.xml',
+ 'report/report_event_question_view.xml',
+ 'security/ir.model.access.csv',
+ ],
+ 'demo': [
+ 'data/demo.xml',
+ ],
+ 'installable': True,
+}
diff --git a/addons/website_event_questions/controllers/__init__.py b/addons/website_event_questions/controllers/__init__.py
new file mode 100644
index 00000000000..bbd183e955b
--- /dev/null
+++ b/addons/website_event_questions/controllers/__init__.py
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+import main
diff --git a/addons/website_event_questions/controllers/main.py b/addons/website_event_questions/controllers/main.py
new file mode 100644
index 00000000000..7d78d7fa11e
--- /dev/null
+++ b/addons/website_event_questions/controllers/main.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+
+from openerp.addons.website_event.controllers.main import website_event
+
+
+class website_event(website_event):
+
+ def _process_registration_details(self, details):
+ ''' Process data posted from the attendee details form. '''
+ registrations = super(website_event, self)._process_registration_details(details)
+ for registration in registrations:
+ answer_ids = []
+ for key, value in registration.iteritems():
+ if key.startswith('answer_ids-'):
+ answer_ids.append([4, int(value)])
+ registration['answer_ids'] = answer_ids
+ return registrations
diff --git a/addons/website_event_questions/data/demo.xml b/addons/website_event_questions/data/demo.xml
new file mode 100644
index 00000000000..e413de1ae85
--- /dev/null
+++ b/addons/website_event_questions/data/demo.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+<openerp>
+ <data>
+
+ <record id="event_question_0" model="event.question">
+ <field name="title">Kind of partner</field>
+ <field name="event_id" ref="event.event_1"/>
+ <field name="sequence">1</field>
+ </record>
+ <record id="event_question_1" model="event.question">
+ <field name="title">Veggie</field>
+ <field name="event_id" ref="event.event_1"/>
+ <field name="sequence">2</field>
+ <field name="is_individual" eval="True"/>
+ </record>
+ <record id="event_question_2" model="event.question">
+ <field name="title">Accommodation</field>
+ <field name="event_id" ref="event.event_1"/>
+ <field name="sequence">3</field>
+ </record>
+
+ <record id="event_suggestion_0_0" model="event.answer">
+ <field name="name">Gold</field>
+ <field name="question_id" ref="event_question_0"/>
+ <field name="sequence">3</field>
+ </record>
+ <record id="event_suggestion_0_1" model="event.answer">
+ <field name="name">Silver</field>
+ <field name="question_id" ref="event_question_0"/>
+ <field name="sequence">2</field>
+ </record>
+ <record id="event_suggestion_0_2" model="event.answer">
+ <field name="name">Bronze</field>
+ <field name="question_id" ref="event_question_0"/>
+ <field name="sequence">1</field>
+ </record>
+
+ <record id="event_suggestion_1_0" model="event.answer">
+ <field name="name">Yes</field>
+ <field name="question_id" ref="event_question_1"/>
+ <field name="sequence">2</field>
+ </record>
+ <record id="event_suggestion_1_1" model="event.answer">
+ <field name="name">No</field>
+ <field name="question_id" ref="event_question_1"/>
+ <field name="sequence">1</field>
+ </record>
+
+ <record id="event_suggestion_2_0" model="event.answer">
+ <field name="name">Personal</field>
+ <field name="question_id" ref="event_question_2"/>
+ <field name="sequence">1</field>
+ </record>
+ <record id="event_suggestion_2_1" model="event.answer">
+ <field name="name">In Charge</field>
+ <field name="question_id" ref="event_question_2"/>
+ <field name="sequence">2</field>
+ </record>
+
+ <record id="event.reg_1_1" model="event.registration">
+ <field name="answer_ids" eval="[(4, ref('event_suggestion_0_0')), (4, ref('event_suggestion_1_1')), (4, ref('event_suggestion_2_0'))]"/>
+ </record>
+ <record id="event.reg_1_2" model="event.registration">
+ <field name="answer_ids" eval="[(4, ref('event_suggestion_0_2')), (4, ref('event_suggestion_1_1')), (4, ref('event_suggestion_2_0'))]"/>
+ </record>
+ <record id="event.reg_1_3" model="event.registration">
+ <field name="answer_ids" eval="[(4, ref('event_suggestion_0_0')), (4, ref('event_suggestion_1_0')), (4, ref('event_suggestion_2_1'))]"/>
+ </record>
+
+ </data>
+</openerp>
diff --git a/addons/website_event_questions/models/__init__.py b/addons/website_event_questions/models/__init__.py
new file mode 100644
index 00000000000..80f7716c2e1
--- /dev/null
+++ b/addons/website_event_questions/models/__init__.py
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+import event
diff --git a/addons/website_event_questions/models/event.py b/addons/website_event_questions/models/event.py
new file mode 100644
index 00000000000..3d9165357b7
--- /dev/null
+++ b/addons/website_event_questions/models/event.py
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+
+from openerp import models, fields
+
+
+class EventEvent(models.Model):
+ """ Override Event model to add optional questions when buying tickets. """
+ _inherit = 'event.event'
+
+ question_ids = fields.One2many('event.question', 'event_id', 'Questions')
+ general_question_ids = fields.One2many('event.question', 'event_id', 'Questions',
+ domain=[('is_individual', '=', False)])
+ specific_question_ids = fields.One2many('event.question', 'event_id', 'Questions',
+ domain=[('is_individual', '=', True)])
+
+
+class EventRegistrationAnswer(models.Model):
+ ''' This m2m table has to be explicitly instanciated as we need unique ids
+ in the reporting view event.question.report.
+
+ This model is purely technical. '''
+
+ _name = 'event.registration.answer'
+ _table = 'event_registration_answer'
+
+ event_answer_id = fields.Many2one('event.answer', required=True)
+ event_registration_id = fields.Many2one('event.registration', required=True)
+
+
+class EventRegistration(models.Model):
+ """ Store answers on attendees. """
+ _inherit = 'event.registration'
+
+ answer_ids = fields.Many2many('event.answer', 'event_registration_answer', string='Answers')
+
+
+class EventQuestion(models.Model):
+ _name = 'event.question'
+ _rec_name = 'title'
+ _order = 'sequence,id'
+
+ title = fields.Char(required=True, translate=True)
+ event_id = fields.Many2one('event.event', required=True, ondelete='cascade')
+ answer_ids = fields.One2many('event.answer', 'question_id', "Answers", required=True)
+ sequence = fields.Integer(default=10)
+ is_individual = fields.Boolean('Ask each attendee',
+ help="If True, this question will be asked for every attendee of a reservation. If "
+ "not it will be asked only once and its value propagated to every attendees.")
+
+
+class EventAnswer(models.Model):
+ _name = 'event.answer'
+ _order = 'sequence,id'
+
+ name = fields.Char('Answer', required=True, translate=True)
+ question_id = fields.Many2one('event.question', required=True, ondelete='cascade')
+ sequence = fields.Integer(default=10)
diff --git a/addons/website_event_questions/report/__init__.py b/addons/website_event_questions/report/__init__.py
new file mode 100644
index 00000000000..5e33c199720
--- /dev/null
+++ b/addons/website_event_questions/report/__init__.py
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+import report_event_registrations_questions
diff --git a/addons/website_event_questions/report/report_event_question_view.xml b/addons/website_event_questions/report/report_event_question_view.xml
new file mode 100644
index 00000000000..4f98b33fc9e
--- /dev/null
+++ b/addons/website_event_questions/report/report_event_question_view.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+
+ <!-- Graph view for question analysis-->
+ <record model="ir.ui.view" id="view_event_question_report_graph">
+ <field name="name">event.question.report.graph</field>
+ <field name="model">event.question.report</field>
+ <field name="arch" type="xml">
+ <graph string="Questions Analysis">
+ <field name="answer_id"/>
+ <field name="question_id"/>
+ </graph>
+ </field>
+ </record>
+
+ <!-- Pivot view for question analysis -->
+ <record model="ir.ui.view" id="view_event_question_report_pivot">
+ <field name="name">event.question.report.pivot</field>
+ <field name="model">event.question.report</field>
+ <field name="arch" type="xml">
+ <pivot string="Questions Analysis" disable_linking="True">
+ <field name="event_id" type="row"/>
+ <field name="attendee_id" type="row"/>
+ <field name="question_id" type="col"/>
+ <field name="answer_id" type="col"/>
+ </pivot>
+ </field>
+ </record>
+
+ <!-- Seach view for question analysis-->
+ <record model="ir.ui.view" id="view_event_question_report_search">
+ <field name="name">event.question.report.search</field>
+ <field name="model">event.question.report</field>
+ <field name="arch" type="xml">
+ <search string="Questions Analysis">
+ <field name="event_id" string="Event"/>
+ <field name="attendee_id" string="Registration"/>
+ <group expand="1" string="Group By">
+ <filter string="Event" context="{'group_by': 'event_id'}" />
+ <filter string="Question" context="{'group_by': 'question_id'}"/>
+ <filter string="Answer" context="{'group_by': 'answer_id'}" />
+ </group>
+ </search>
+ </field>
+ </record>
+
+ <!-- Action for reporting -->
+ <record model="ir.actions.act_window" id="action_event_question_report">
+ <field name="name">Questions Analysis</field>
+ <field name="res_model">event.question.report</field>
+ <field name="view_type">form</field>
+ <field name="view_mode">pivot,graph</field>
+ </record>
+
+ <!-- Menu -->
+ <menuitem name="Questions Analysis" id="menu_report_event_questions"
+ parent="event.menu_reporting_events" action="action_event_question_report" sequence="4"/>
+
+ </data>
+</openerp>
diff --git a/addons/website_event_questions/report/report_event_registrations_questions.py b/addons/website_event_questions/report/report_event_registrations_questions.py
new file mode 100644
index 00000000000..0e4f949ca97
--- /dev/null
+++ b/addons/website_event_questions/report/report_event_registrations_questions.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+
+from openerp import fields, models, tools
+
+
+class ReportEventRegistrationQuestions(models.Model):
+ _name = "event.question.report"
+ _auto = False
+
+ attendee_id = fields.Many2one(comodel_name='event.registration', string='Registration')
+ question_id = fields.Many2one(comodel_name='event.question', string='Question')
+ answer_id = fields.Many2one(comodel_name='event.answer', string='Answer')
+ event_id = fields.Many2one(comodel_name='event.event', string='Event')
+
+ def init(self, cr):
+ """ Event Question main report """
+ tools.drop_view_if_exists(cr, 'event_question_report')
+ cr.execute(""" CREATE VIEW event_question_report AS (
+ SELECT
+ att_answer.id as id,
+ att_answer.event_registration_id as attendee_id,
+ answer.question_id as question_id,
+ answer.id as answer_id,
+ question.event_id as event_id
+ FROM
+ event_registration_answer as att_answer
+ LEFT JOIN
+ event_answer as answer ON answer.id = att_answer.event_answer_id
+ LEFT JOIN
+ event_question as question ON question.id = answer.question_id
+ GROUP BY
+ attendee_id,
+ event_id,
+ question_id,
+ answer_id,
+ att_answer.id
+ )""")
diff --git a/addons/website_event_questions/security/ir.model.access.csv b/addons/website_event_questions/security/ir.model.access.csv
new file mode 100644
index 00000000000..79ab8690426
--- /dev/null
+++ b/addons/website_event_questions/security/ir.model.access.csv
@@ -0,0 +1,7 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+event_question_all,event.question.all,model_event_question,,1,0,0,0
+event_question_event_user,event.question.event.user,model_event_question,event.group_event_user,1,1,1,1
+event_answer_all,event.answer.all,model_event_answer,,1,0,0,0
+event_answer_event_user,event.answer.event.user,model_event_answer,event.group_event_user,1,1,1,1
+event_question_report_all,event.question.report.all,model_event_question_report,event.group_event_user,1,1,1,1
+event_registration_answer_all,access_event_registration_answer,model_event_registration_answer,,1,1,1,1
diff --git a/addons/website_event_questions/views/website_event_questions_backend.xml b/addons/website_event_questions/views/website_event_questions_backend.xml
new file mode 100644
index 00000000000..a4428bd8094
--- /dev/null
+++ b/addons/website_event_questions/views/website_event_questions_backend.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+
+<record model="ir.ui.view" id="view_event_question_form">
+ <field name="name">event.question.form</field>
+ <field name="model">event.question</field>
+ <field name="arch" type="xml">
+ <form string="Question">
+ <h1><field name="title" /></h1>
+ <field name="is_individual"/>
+ <label for="is_individual"/>
+ <field name="answer_ids">
+ <tree editable="bottom">
+ <field name="sequence" widget="handle" />
+ <field name="name"/>
+ </tree>
+ </field>
+ </form>
+ </field>
+</record>
+
+<record model="ir.ui.view" id="view_event_answer_simplified_form">
+ <field name="name">event.answer.simplified.form</field>
+ <field name="model">event.answer</field>
+ <field name="arch" type="xml">
+ <form string="Question">
+ <group>
+ <field name="name"/>
+ </group>
+ </form>
+ </field>
+</record>
+
+<record model="ir.ui.view" id="view_event_form_inherit_question">
+ <field name="name">event.form.inherit.question</field>
+ <field name="model">event.event</field>
+ <field name="inherit_id" ref="event.view_event_form"/>
+ <field name="arch" type="xml">
+ <data>
+ <xpath expr="//notebook" position="inside">
+ <page string="Questions">
+ <field name="question_ids" nolabel="1">
+ <tree>
+ <field name="sequence" widget="handle" />
+ <field name="title"/>
+ <field name="is_individual"/>
+ <field name="answer_ids"/>
+ </tree>
+ </field>
+ </page>
+ </xpath>
+ </data>
+ </field>
+</record>
+
+<record model="ir.ui.view" id="view_event_registration_form_inherit_question">
+ <field name="name">event.registration.form.inherit.question</field>
+ <field name="model">event.registration</field>
+ <field name="inherit_id" ref="event.view_event_registration_form" />
+ <field name="arch" type="xml">
+ <group name="event" position="inside">
+ <field name="answer_ids" widget="many2many_tags" readonly="1"/>
+ </group>
+ </field>
+</record>
+
+<record model="ir.ui.view" id="view_registration_search_inherit_question">
+ <field name="name">event.registration.search.inherit.question</field>
+ <field name="model">event.registration</field>
+ <field name="inherit_id" ref="event.view_registration_search"/>
+ <field name="arch" type="xml">
+ <search position="inside">
+ <field name="answer_ids" string="Answers"/>
+ </search>
+ </field>
+</record>
+
+</odoo>
diff --git a/addons/website_event_questions/views/website_event_questions_templates.xml b/addons/website_event_questions/views/website_event_questions_templates.xml
new file mode 100644
index 00000000000..ec9c055e2ae
--- /dev/null
+++ b/addons/website_event_questions/views/website_event_questions_templates.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+
+<template id="registration_attendee_details_questions" inherit_id="website_event.registration_attendee_details" name="Registration Attendee Details with questions">
+ <data>
+ <!-- Attendee specific questions -->
+ <xpath expr="//t[@name='attendee_loop']" position="inside">
+ <t t-if="event.specific_question_ids">
+ <div class="row mb32">
+ <div class="col-md-4" t-foreach='event.specific_question_ids' t-as='question'>
+ <div class="input-group input-group-sm">
+ <span class="input-group-addon"><t t-esc="question.title"/></span>
+ <select t-attf-name="#{counter}-answer_ids-#{question.id}" class="form-control" required="true">
+ <t t-foreach='question.answer_ids' t-as="answer">
+ <option t-esc='answer.name' t-att-value='answer.id'/>
+ </t>
+ </select>
+ </div>
+ </div>
+ </div>
+ </t>
+ </xpath>
+
+ <!-- Generic questions -->
+ <xpath expr="//div[@class='container']/t[last()]" position="after">
+ <t t-if="event.general_question_ids">
+ <h4 class="page-header mt32"><strong>Last questions</strong></h4>
+ <div class="row">
+ <div class="col-md-4" t-foreach='event.general_question_ids' t-as='question'>
+ <div class="input-group">
+ <span class="input-group-addon"><t t-esc='question.title'/></span>
+ <select t-attf-name="0-answer_ids-#{question.id}" class="form-control" required="true">
+ <t t-foreach='question.answer_ids' t-as="answer">
+ <option t-esc='answer.name' t-att-value='answer.id'/>
+ </t>
+ </select>
+ </div>
+ </div>
+ </div>
+ </t>
+ </xpath>
+
+ </data>
+</template>
+
+</odoo>