[MERGE][IMP] Reporting system for surveys

bzr revid: rim@openerp.com-20140408135908-0h3qiohc84kx4b2r
This commit is contained in:
Richard Mathot (OpenERP) 2014-04-08 15:59:08 +02:00
commit d197bab150
5 changed files with 383 additions and 271 deletions

View File

@ -22,9 +22,7 @@
import json
import logging
import werkzeug
from collections import Counter
from datetime import datetime
from itertools import product
from math import ceil
from openerp import SUPERUSER_ID
@ -287,118 +285,65 @@ class WebsiteSurvey(http.Controller):
type='http', auth='user', multilang=True, website=True)
def survey_reporting(self, survey, token=None, **post):
'''Display survey Results & Statistics for given survey.'''
result_template, current_filters, filter_display_data = 'survey.result', [], []
result_template, current_filters, filter_display_data, filter_finish = 'survey.result', [], [], False
survey_obj = request.registry['survey.survey']
if not survey.user_input_ids or not [input_id.id for input_id in survey.user_input_ids if input_id.state != 'new']:
result_template = 'survey.no_result'
if post:
current_filters, filter_display_data = self.filter_input_ids(post)
if 'finished' in post:
post.pop('finished')
filter_finish = True
if post or filter_finish:
filter_data = self.get_filter_data(post)
current_filters = survey_obj.filter_input_ids(request.cr, request.uid, filter_data, filter_finish, context=request.context)
filter_display_data = survey_obj.get_filter_display_data(request.cr, request.uid, filter_data, context=request.context)
return request.website.render(result_template,
{'survey': survey,
'prepare_result': self.prepare_result,
'get_input_summary': self.get_input_summary,
'get_graph_data': self.get_graph_data,
{'survey_dict': self.prepare_result_dict(survey, current_filters),
'page_range': self.page_range,
'current_filters': current_filters,
'filter_display_data': filter_display_data
'filter_display_data': filter_display_data,
'filter_finish': filter_finish
})
def filter_input_ids(self, filters):
'''If user applies any filters, then this function returns list of
filtered user_input_id and label's strings for display data in web'''
cr, uid, context = request.cr, request.uid, request.context
question_obj = request.registry['survey.question']
input_obj = request.registry['survey.user_input_line']
input_line_obj = request.registry['survey.user_input_line']
label_obj = request.registry['survey.label']
domain_filter, choice, filter_display_data = [], [], []
def prepare_result_dict(self,survey, current_filters=[]):
"""Returns dictionary having values for rendering template"""
survey_obj = request.registry['survey.survey']
result = {'survey':survey, 'page_ids': []}
for page in survey.page_ids:
page_dict = {'page': page, 'question_ids': []}
for question in page.question_ids:
question_dict = {'question':question, 'input_summary':survey_obj.get_input_summary(request.cr, request.uid, question, current_filters, context=request.context), 'prepare_result':survey_obj.prepare_result(request.cr, request.uid, question, current_filters, context=request.context), 'graph_data': self.get_graph_data(question, current_filters)}
page_dict['question_ids'].append(question_dict)
result['page_ids'].append(page_dict)
return result
#if user add some random data in query URI
try:
for ids in filters:
def get_filter_data(self, post):
"""Returns data used for filtering the result"""
filters = []
for ids in post:
#if user add some random data in query URI, ignore it
try:
row_id, answer_id = ids.split(',')
question_id = filters[ids]
question = question_obj.browse(cr, uid, int(question_id), context=context)
if row_id == '0':
choice.append(int(answer_id))
labels = label_obj.browse(cr, uid, [int(answer_id)], context=context)
else:
domain_filter.extend(['|', ('value_suggested_row.id', '=', int(row_id)), ('value_suggested.id', '=', int(answer_id))])
labels = label_obj.browse(cr, uid, [int(row_id), int(answer_id)], context=context)
filter_display_data.append({'question_text': question.question, 'labels': [label.value for label in labels]})
if choice:
domain_filter.insert(0, ('value_suggested.id', 'in', choice))
else:
domain_filter = domain_filter[1:]
except:
#if user add some random data in query URI
return([], [])
line_ids = input_line_obj.search(cr, uid, domain_filter, context=context)
filtered_input_ids = [input.user_input_id.id for input in input_obj.browse(cr, uid, line_ids, context=context)]
return (filtered_input_ids, filter_display_data)
filters.append({'row_id': int(row_id), 'answer_id': int(answer_id)})
except:
return filters
return filters
def page_range(self, total_record, limit):
'''Returns number of pages required for pagination'''
total = ceil(total_record / float(limit))
return range(1, int(total + 1))
def prepare_result(self, question, current_filters=[]):
'''Prepare statistical data for questions by counting number of vote per choice on basis of filter'''
#Calculate and return statistics for choice
if question.type in ['simple_choice', 'multiple_choice']:
result_summary = {}
[result_summary.update({label.id: {'text': label.value, 'count': 0, 'answer_id': label.id}}) for label in question.labels_ids]
for input_line in question.user_input_line_ids:
if result_summary.get(input_line.value_suggested.id) and (not(current_filters) or input_line.user_input_id.id in current_filters):
result_summary[input_line.value_suggested.id]['count'] += 1
result_summary = result_summary.values()
#Calculate and return statistics for matrix
if question.type == 'matrix':
rows, answers, res = {}, {}, {}
[rows.update({label.id: label.value}) for label in question.labels_ids_2]
[answers.update({label.id: label.value}) for label in question.labels_ids]
for cell in product(rows.keys(), answers.keys()):
res[cell] = 0
for input_line in question.user_input_line_ids:
if not(current_filters) or input_line.user_input_id.id in current_filters:
res[(input_line.value_suggested_row.id, input_line.value_suggested.id)] += 1
result_summary = {'answers': answers, 'rows': rows, 'result': res}
#Calculate and return statistics for free_text, textbox, datetime
if question.type in ['free_text', 'textbox', 'datetime']:
result_summary = []
for input_line in question.user_input_line_ids:
if not(current_filters) or input_line.user_input_id.id in current_filters:
result_summary.append(input_line)
#Calculate and return statistics for numerical_box
if question.type == 'numerical_box':
result_summary = {'input_lines': []}
all_inputs = []
for input_line in question.user_input_line_ids:
if not(current_filters) or input_line.user_input_id.id in current_filters:
all_inputs.append(input_line.value_number)
result_summary['input_lines'].append(input_line)
result_summary.update({'average': round(sum(all_inputs) / len(all_inputs), 2),
'max': round(max(all_inputs), 2),
'min': round(min(all_inputs), 2),
'most_comman': Counter(all_inputs).most_common(5)})
return result_summary
@http.route(['/survey/results/graph/<model("survey.question"):question>'],
type='http', auth='user', multilang=True, website=True)
def get_graph_data(self, question, **post):
'''Returns appropriate formated data required by graph library on basis of filter'''
current_filters = safe_eval(post.get('current_filters', '[]'))
def get_graph_data(self, question, current_filters=[]):
'''Returns formatted data required by graph library on basis of filter'''
survey_obj = request.registry['survey.survey']
result = []
if question.type in ['simple_choice', 'multiple_choice']:
if question.type == 'multiple_choice':
result.append({'key': str(question.question),
'values': self.prepare_result(question, current_filters)})
'values': survey_obj.prepare_result(request.cr, request.uid, question, current_filters, context=request.context)})
if question.type == 'simple_choice':
result = survey_obj.prepare_result(request.cr, request.uid, question, current_filters, context=request.context)
if question.type == 'matrix':
data = self.prepare_result(question, current_filters)
data = survey_obj.prepare_result(request.cr, request.uid, question, current_filters, context=request.context)
for answer in data['answers']:
values = []
for res in data['result']:
@ -407,21 +352,6 @@ class WebsiteSurvey(http.Controller):
result.append({'key': data['answers'].get(answer), 'values': values})
return json.dumps(result)
def get_input_summary(self, question, current_filters=[]):
'''Returns overall summary of question e.g. answered, skipped, total_inputs on basis of filter'''
result = {}
if question.survey_id.user_input_ids:
total_input_ids = current_filters or [input_id.id for input_id in question.survey_id.user_input_ids if input_id.state != 'new']
result['total_inputs'] = len(total_input_ids)
question_input_ids = []
for user_input in question.user_input_line_ids:
if not user_input.skipped:
question_input_ids.append(user_input.user_input_id.id)
result['answered'] = len(set(question_input_ids) & set(total_input_ids))
result['skipped'] = result['total_inputs'] - result['answered']
return result
def dict_soft_update(dictionary, key, value):
''' Insert the pair <key>: <value> into the <dictionary>. If <key> is
already present, this function will append <value> to the list of

View File

@ -1,42 +1,53 @@
.only_right_radius{
border-top-right-radius:2em;
border-bottom-right-radius:2em;
border-top-left-radius:0;
border-bottom-left-radius:0;
.only_right_radius {
border-top-right-radius: 2em;
border-bottom-right-radius: 2em;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.only_left_radius{
border-top-right-radius:0;
border-bottom-right-radius:0;
border-top-left-radius:2em;
border-bottom-left-radius:2em;
.only_left_radius {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-top-left-radius: 2em;
border-bottom-left-radius: 2em;
}
.no_radius{
border-radius:0;
.no_radius {
border-radius: 0;
}
.clear_survey_filter{
cursor:pointer;
.clear_survey_filter, .filter-all, .filter-finished{
cursor: pointer;
}
.nvtooltip h5 {
margin: 0;
line-height: 18px;
font-weight: bold;
background-color: rgba(247,247,247,0.75);
text-align: center;
border-bottom: 1px solid #ebebeb;
-webkit-border-radius: 5px 5px 0 0;
-moz-border-radius: 5px 5px 0 0;
border-radius: 5px 5px 0 0;
margin: 0;
line-height: 18px;
font-weight: bold;
background-color: rgba(247,247,247,0.75);
text-align: center;
border-bottom: 1px solid #ebebeb;
-webkit-border-radius: 5px 5px 0 0;
-moz-border-radius: 5px 5px 0 0;
border-radius: 5px 5px 0 0;
}
.survey_answer i{
padding:3px;
cursor:pointer;
.survey_answer i {
padding:3px;
cursor:pointer;
}
.survey_answer i.invisible{
visibility: hidden!important;
.survey_answer i.invisible {
visibility: hidden!important;
}
@media print {
.tab-content > .tab-pane {
display: block;
}
.tab-content > .survey_graph > svg {
width: 1150px;
}
}

View File

@ -62,29 +62,38 @@ $(document).ready(function () {
//initialize discreteBar Chart
function init_bar_chart(){
return nv.models.discreteBarChart()
.x(function(d) { return d.text; })
.y(function(d) { return d.count; })
.staggerLabels(true)
.tooltips(false)
.showValues(true);
.x(function(d) { return d.text; })
.y(function(d) { return d.count; })
.staggerLabels(true)
.tooltips(false)
.showValues(true);
}
//initialize Pie Chart
function init_pie_chart(){
return nv.models.pieChart()
.x(function(d) { return d.text; })
.y(function(d) { return d.count; })
.showLabels(false);
}
//load chart to svg element chart:initialized chart, response:AJAX response, quistion_id:if of survey question, tick_limit:text length limit
function load_chart(chart, response, question_id, tick_limit){
function load_chart(chart, response, question_id, tick_limit, graph_type){
// Custom Tick fuction for replacing long text with '...'
var customtick_function = function(d){
if(! this || d.length <= tick_limit){
return d;
}
else{
return d.slice(0,tick_limit)+'...';
return d.slice(0,tick_limit) + '...';
}
};
chart.xAxis
.tickFormat(customtick_function);
chart.yAxis
.tickFormat(d3.format('d'));
if (graph_type != 'pie'){
chart.xAxis
.tickFormat(customtick_function);
chart.yAxis
.tickFormat(d3.format('d'));
}
d3.select('#graph_question_' + question_id + ' svg')
.datum(response)
.transition().duration(500).call(chart);
@ -96,42 +105,42 @@ $(document).ready(function () {
$.each(survey_graphs, function(index, graph){
var question_id = $(graph).attr("data-question_id");
var graph_type = $(graph).attr("data-graph_type");
var current_filters = $(graph).attr("data-current_filters");
console.log(current_filters);
$.ajax({
url: '/survey/results/graph/'+question_id,
type: 'POST',
dataType: 'json',
data:{'current_filters': current_filters},
success: function(response, status, xhr, wfe){
if(graph_type == 'multi_bar'){
nv.addGraph(function(){
var chart = init_multibar_chart();
return load_chart(chart,response,question_id,25);
});
}
else if(graph_type == 'bar'){
nv.addGraph(function() {
var chart = init_bar_chart();
return load_chart(chart,response,question_id,35);
});
}
}
});
var graph_data = JSON.parse($(graph).attr("graph-data"));
if(graph_type == 'multi_bar'){
nv.addGraph(function(){
var chart = init_multibar_chart();
return load_chart(chart, graph_data, question_id, 25);
});
}
else if(graph_type == 'bar'){
nv.addGraph(function() {
var chart = init_bar_chart();
return load_chart(chart, graph_data, question_id, 35);
});
}
else if(graph_type == 'pie'){
nv.addGraph(function() {
var chart = init_pie_chart();
return load_chart(chart, graph_data, question_id, 25, 'pie');
});
}
});
// Script for filter
$('td.survey_answer').hover(function(){$(this).find('i.fa-filter').removeClass('invisible');},function(){$(this).find('i.fa-filter').addClass('invisible');});
$('td.survey_answer').hover(function(){
$(this).find('i.fa-filter').removeClass('invisible');
}, function(){
$(this).find('i.fa-filter').addClass('invisible');
});
$('td.survey_answer i.fa-filter').click(function(){
var cell=$(this);
var question_id = cell.attr('data-question_id');
var cell = $(this);
var row_id = cell.attr('data-row_id') | 0;
var answer_id = cell.attr('data-answer_id');
if(document.URL.indexOf("?") == -1){
window.location.href = document.URL+'?' + encodeURI(row_id + ','+answer_id + '=' + question_id);
window.location.href = document.URL + '?' + encodeURI(row_id + ',' + answer_id);
}
else{
window.location.href = document.URL+'&' + encodeURI(row_id + ','+answer_id + '=' + question_id);
else {
window.location.href = document.URL + '&' + encodeURI(row_id + ',' + answer_id);
}
});
@ -139,6 +148,30 @@ $(document).ready(function () {
$('.clear_survey_filter').click(function(){
window.location.href = document.URL.substring(0,document.URL.indexOf("?"));
});
$('span.filter-all').click(function(){
event.preventDefault();
if(document.URL.indexOf("finished") != -1){
window.location.href = document.URL.replace('?finished&','?').replace('&finished&','&').replace('?finished','').replace('&finished','');
}
}).hover(function(){
if(document.URL.indexOf("finished") == -1){
$(this)[0].style.cursor = 'default';
}
});
// toggle finished/all surveys filter
$('span.filter-finished').click(function(){
event.preventDefault();
if(document.URL.indexOf("?") == -1){
window.location.href = document.URL + '?' + encodeURI('finished');
}
else if(document.URL.indexOf("finished") == -1){
window.location.href = document.URL + '&' + encodeURI('finished');
}
}).hover(function(){
if(document.URL.indexOf("finished") != -1){
$(this)[0].style.cursor = 'default';
}
});
console.debug("[survey] Survey Result JS loaded!");
});

View File

@ -24,6 +24,8 @@ from openerp.tools.translate import _
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DF
from openerp.addons.website.models.website import slug
from urlparse import urljoin
from itertools import product
from collections import Counter
import datetime
import logging
@ -133,6 +135,126 @@ class survey_survey(osv.Model):
res[survey.id] = urljoin(base_url, "survey/results/%s" % slug(survey))
return res
def filter_input_ids(self, cr, uid, filters, finished=False, context=None):
'''If user applies any filters, then this function returns list of
filtered user_input_id and label's strings for display data in web.
:param filters: list of dictionary (having: row_id, ansewr_id)
:param finished: True for completely filled survey,Falser otherwise.
:returns list of filtered user_input_ids.
'''
if context is None:
context = {}
if filters:
input_line_obj = self.pool.get('survey.user_input_line')
domain_filter, choice, filter_display_data = [], [], []
for filter in filters:
row_id, answer_id = filter['row_id'], filter['answer_id']
if row_id == 0:
choice.append(answer_id)
else:
domain_filter.extend(['|', ('value_suggested_row.id', '=', row_id), ('value_suggested.id', '=', answer_id)])
if choice:
domain_filter.insert(0, ('value_suggested.id', 'in', choice))
else:
domain_filter = domain_filter[1:]
line_ids = input_line_obj.search(cr, uid, domain_filter, context=context)
filtered_input_ids = [input.user_input_id.id for input in input_line_obj.browse(cr, uid, line_ids, context=context)]
else:
filtered_input_ids, filter_display_data = [], []
if finished:
user_input = self.pool.get('survey.user_input')
if not filtered_input_ids:
current_filters = user_input.search(cr, uid, [], context=context)
user_input_objs = user_input.browse(cr, uid, current_filters, context=context)
else:
user_input_objs = user_input.browse(cr, uid, filtered_input_ids, context=context)
return [input.id for input in user_input_objs if input.state == 'done']
return filtered_input_ids
def get_filter_display_data(self, cr, uid, filters, context):
'''Returns data to display current filters
:param filters: list of dictionary (having: row_id, answer_id)
:param finished: True for completely filled survey, False otherwise.
:returns list of dict having data to display filters.
'''
filter_display_data = []
if filters:
question_obj = self.pool.get('survey.question')
label_obj = self.pool.get('survey.label')
for filter in filters:
row_id, answer_id = filter['row_id'], filter['answer_id']
question_id = label_obj.browse(cr, uid, answer_id, context=context).question_id.id
question = question_obj.browse(cr, uid, question_id, context=context)
if row_id == 0:
labels = label_obj.browse(cr, uid, [answer_id], context=context)
else:
labels = label_obj.browse(cr, uid, [row_id, answer_id], context=context)
filter_display_data.append({'question_text': question.question, 'labels': [label.value for label in labels]})
return filter_display_data
def prepare_result(self, cr, uid, question, current_filters=[], context=None):
''' Compute statistical data for questions by counting number of vote per choice on basis of filter '''
if context is None:
context = {}
#Calculate and return statistics for choice
if question.type in ['simple_choice', 'multiple_choice']:
result_summary = {}
[result_summary.update({label.id: {'text': label.value, 'count': 0, 'answer_id': label.id}}) for label in question.labels_ids]
for input_line in question.user_input_line_ids:
if result_summary.get(input_line.value_suggested.id) and (not(current_filters) or input_line.user_input_id.id in current_filters):
result_summary[input_line.value_suggested.id]['count'] += 1
result_summary = result_summary.values()
#Calculate and return statistics for matrix
if question.type == 'matrix':
rows, answers, res = {}, {}, {}
[rows.update({label.id: label.value}) for label in question.labels_ids_2]
[answers.update({label.id: label.value}) for label in question.labels_ids]
for cell in product(rows.keys(), answers.keys()):
res[cell] = 0
for input_line in question.user_input_line_ids:
if not(current_filters) or input_line.user_input_id.id in current_filters:
res[(input_line.value_suggested_row.id, input_line.value_suggested.id)] += 1
result_summary = {'answers': answers, 'rows': rows, 'result': res}
#Calculate and return statistics for free_text, textbox, datetime
if question.type in ['free_text', 'textbox', 'datetime']:
result_summary = []
for input_line in question.user_input_line_ids:
if not(current_filters) or input_line.user_input_id.id in current_filters:
result_summary.append(input_line)
#Calculate and return statistics for numerical_box
if question.type == 'numerical_box':
result_summary = {'input_lines': []}
all_inputs = []
for input_line in question.user_input_line_ids:
if not(current_filters) or input_line.user_input_id.id in current_filters:
all_inputs.append(input_line.value_number)
result_summary['input_lines'].append(input_line)
if all_inputs:
result_summary.update({'average': round(sum(all_inputs) / len(all_inputs), 2),
'max': round(max(all_inputs), 2),
'min': round(min(all_inputs), 2),
'most_comman': Counter(all_inputs).most_common(5)})
return result_summary
def get_input_summary(self, cr, uid, question, current_filters=[], context=None):
''' Returns overall summary of question e.g. answered, skipped, total_inputs on basis of filter '''
if context is None:
context = {}
result = {}
if question.survey_id.user_input_ids:
total_input_ids = current_filters or [input_id.id for input_id in question.survey_id.user_input_ids if input_id.state != 'new']
result['total_inputs'] = len(total_input_ids)
question_input_ids = []
for user_input in question.user_input_line_ids:
if not user_input.skipped:
question_input_ids.append(user_input.user_input_id.id)
result['answered'] = len(set(question_input_ids) & set(total_input_ids))
result['skipped'] = result['total_inputs'] - result['answered']
return result
# Model fields #
_columns = {

View File

@ -13,42 +13,66 @@
<div class="oe_structure" />
<div class="container">
<div class="jumbotron mt32">
<t t-set="survey" t-value="survey_dict['survey']"/>
<h1><span t-field="survey.title"></span> <span style="font-size:1.5em;" class="fa fa-bar-chart-o pull-right "/></h1>
<h2><span t-field="survey.description"></span></h2>
</div>
<div t-if="filter_display_data" class="filteres">
<span><h3><span class="fa fa-filter"></span> Filters <small class="pull-right clear_survey_filter"> <i class="fa fa-times"></i> Clear All Filters</small></h3></span>
<span t-foreach="filter_display_data" t-as="filter_data">
<span class="label label-primary only_left_radius"><i class="fa fa-filter"></i></span><span class="label label-primary no_radius" t-esc="filter_data['question_text']"></span><span class="label label-success only_right_radius" t-esc="' > '.join(filter_data['labels'])"></span>
</span>
<div class="panel panel-default hidden-print">
<div class="panel-heading"><span class="fa fa-filter"></span> Filters <span t-if="filter_display_data" class="pull-right text-primary clear_survey_filter"><i class="fa fa-times"></i> Clear All Filters</span></div>
<div class="panel-body">
<span t-if="filter_finish == True">
<span class="label label-default only_left_radius filter-all">All surveys</span><span class="label label-primary only_right_radius filter-finished">Finished surveys</span>
</span>
<span t-if="filter_finish == False">
<span class="label label-primary only_left_radius filter-all">All surveys</span><span class="label label-default only_right_radius filter-finished">Finished surveys</span>
</span>
<span t-foreach="filter_display_data" t-as="filter_data">
<span class="label label-primary only_left_radius"><i class="fa fa-filter"></i></span><span class="label label-primary no_radius" t-esc="filter_data['question_text']"></span><span class="label label-success only_right_radius" t-esc="' > '.join(filter_data['labels'])"></span>
</span>
</div>
</div>
<div t-foreach='survey.page_ids' t-as='page'>
<div t-foreach="survey_dict['page_ids']" t-as='page_ids'>
<t t-set="page" t-value="page_ids['page']"/>
<h1 class="mt16" t-field='page.title'></h1>
<hr/>
<div t-foreach='page.question_ids' t-as='question' class="mt16">
<t t-set="input_summary" t-value="get_input_summary(question, current_filters)"/>
<div t-foreach="page_ids['question_ids']" t-as='question_ids' class="mt16">
<t t-set="input_summary" t-value="question_ids['input_summary']"/>
<t t-set="question" t-value="question_ids['question']"/>
<t t-set="graph_data" t-value="question_ids['graph_data']"/>
<t t-set="prepare_result" t-value="question_ids['prepare_result']"/>
<h4>
<b>Question </b>
<span t-field='question.question'></span>
<t t-if="question.type == 'matrix'">
<small><span class="label label-default">Matrix: <span t-field='question.matrix_subtype'/></span></small>
</t>
<t t-if="question.type in ['simple_choice', 'multiple_choice']">
<small><span t-field='question.type' class="label label-default"></span></small>
</t>
<span class="pull-right">
<span class="label label-success"><span t-esc="input_summary['answered']"></span> Answered</span>
<span class="label label-danger"><span t-esc="input_summary['skipped']"></span> Skipped</span>
</span>
</h4>
<t t-if="question.description">
<h5><span class="text-muted" t-field="question.description"></span></h5>
<t t-if="input_summary['answered'] != 0">
<t t-if="question.description">
<h5><span class="text-muted" t-field="question.description"></span></h5>
</t>
<t t-if="question.type in ['textbox', 'free_text', 'datetime']">
<t t-call="survey.result_text"></t>
</t>
<t t-if="question.type in ['simple_choice', 'multiple_choice']">
<t t-call="survey.result_choice"></t>
</t>
<t t-if="question.type == 'matrix'">
<t t-call="survey.result_matrix"></t>
</t>
<t t-if="question.type == 'numerical_box'">
<t t-call="survey.result_number"></t>
</t>
</t>
<t t-if="question.type in ['textbox', 'free_text', 'datetime']">
<t t-call="survey.result_text"></t>
</t>
<t t-if="question.type in ['simple_choice', 'multiple_choice']">
<t t-call="survey.result_choice"></t>
</t>
<t t-if="question.type == 'matrix'">
<t t-call="survey.result_matrix"></t>
</t>
<t t-if="question.type == 'numerical_box'">
<t t-call="survey.result_number"></t>
<t t-if="input_summary['answered'] == 0">
<h2 style="padding-top:30px;padding-bottom:30px;text-align:center;" class="text-muted">Sorry, No one answered this question.</h2>
</t>
</div>
</div>
@ -59,78 +83,70 @@
<!-- Result for free_text,textbox and datetime -->
<template id="result_text" name="Text Result">
<t t-if="input_summary['answered'] != 0">
<table class="table table-hover" t-att-id="'table_question_'+str(question.id)">
<thead>
<tr>
<th>#</th>
<th>User Responses</th>
</tr>
</thead>
<tbody>
<t t-set="text_result" t-value="prepare_result(question, current_filters)"></t>
<tr class="hidden" t-foreach="text_result" t-as="user_input">
<td><t t-esc="user_input_index+1"></t></td>
<t t-if="question.type == 'free_text'">
<td>
<span t-field="user_input.value_free_text"></span><br/>
<small><p t-field="user_input.date_create" class="fa fa-calendar oe_date text-muted"></p></small>
<span class="pull-right">
<a t-att-href="user_input.user_input_id.print_url+'/'+user_input.user_input_id.token"> <i class="fa fa-print"></i> Print respondent's answers</a><br/>
</span>
</td>
</t>
<t t-if="question.type == 'textbox'">
<td>
<span t-field="user_input.value_text"></span><br/>
<small><p t-field="user_input.date_create" class="fa fa-calendar oe_date text-muted"></p>
<span class="pull-right">
<a t-att-href="user_input.user_input_id.print_url+'/'+user_input.user_input_id.token"> <i class="fa fa-print"></i> Print respondent's answers</a><br/>
</span>
</small>
</td>
</t>
<t t-if="question.type == 'datetime'">
<td>
<span class="oe_date" t-field="user_input.value_date"></span><br/>
<span class="pull-right">
<a t-att-href="user_input.user_input_id.print_url+'/'+user_input.user_input_id.token"> <i class="fa fa-print"></i> Print respondent's answers</a><br/>
</span>
</td>
</t>
</tr>
</tbody>
</table>
<t t-call="survey.pagination" />
</t>
<t t-if="input_summary['answered'] == 0">
<h2 style="padding-top:30px;padding-bottom:30px;text-align:center;" class="text-muted">Sorry, No one answered this question.</h2>
</t>
<table class="table table-hover table-condensed" t-att-id="'table_question_%d' % question.id">
<thead>
<tr>
<th>#</th>
<th>User Responses</th>
</tr>
</thead>
<tbody>
<t t-set="text_result" t-value="prepare_result"/>
<tr t-foreach="text_result" t-as="user_input">
<td><a t-att-href="'%s/%s' % (user_input.user_input_id.print_url, user_input.user_input_id.token)"><t t-esc="user_input_index + 1"></t></a></td>
<t t-if="question.type == 'free_text'">
<td>
<span t-field="user_input.value_free_text"></span><br/>
</td>
</t>
<t t-if="question.type == 'textbox'">
<td>
<span t-field="user_input.value_text"></span><br/>
</td>
</t>
<t t-if="question.type == 'datetime'">
<td>
<span class="oe_date" t-field="user_input.value_date"></span><br/>
</td>
</t>
</tr>
</tbody>
</table>
<t t-call="survey.pagination" />
</template>
<!-- Result for simple_choice and multiple_choice -->
<template id="result_choice" name="Choice Result">
<div>
<!-- Tabs -->
<ul class="nav nav-tabs">
<li class="active">
<a t-att-href="'#graph_question_'+str(question.id)" data-toggle="tab">
<ul class="nav nav-tabs hidden-print">
<li class="active" t-if="question.type != 'simple_choice'">
<a t-att-href="'#graph_question_%d' % question.id" data-toggle="tab">
<i class="fa fa-bar-chart-o"></i> Graph
</a>
</li>
<li class="active" t-if="question.type == 'simple_choice'">
<a t-att-href="'#graph_question_%d' % question.id" data-toggle="tab">
<i class="fa fa-bar-chart-o"></i> Pie Chart
</a>
</li>
<li>
<a t-att-href="'#data_question_'+str(question.id)" data-toggle="tab">
<a t-att-href="'#data_question_%d' % question.id" data-toggle="tab">
<i class="fa fa-list-alt"></i> Data
</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active survey_graph" t-att-id="'graph_question_'+str(question.id)" t-att-data-question_id="question.id" data-graph_type="bar" t-att-data-current_filters="current_filters">
<div class="tab-pane active survey_graph" t-if="question.type != 'simple_choice'" t-att-id="'graph_question_%d' % question.id" t-att-data-question_id="question.id" data-graph_type="bar" t-att-graph-data="graph_data">
<!-- svg element for drawing bar chart -->
<svg style="height:20em"></svg>
</div>
<div class="tab-pane" t-att-id="'data_question_'+str(question.id)">
<table class="table table-hover">
<div class="tab-pane active survey_graph" t-if="question.type == 'simple_choice'" t-att-id="'graph_question_%d' % question.id" t-att-data-question_id="question.id" data-graph_type="pie" t-att-graph-data="graph_data">
<!-- svg element for drawing pie chart -->
<svg style="height:20em"></svg>
</div>
<div class="tab-pane" t-att-id="'data_question_%d' % question.id">
<table class="table table-hover table-condensed">
<thead>
<tr>
<th>Answer Choices</th>
@ -138,7 +154,7 @@
</tr>
</thead>
<tbody>
<tr t-foreach="prepare_result(question, current_filters)" t-as="user_input">
<tr t-foreach="prepare_result" t-as="user_input">
<td>
<p t-esc="user_input['text']"></p>
</td>
@ -157,29 +173,29 @@
<!-- Result for matrix -->
<template id="result_matrix" name="Matrix Result">
<t t-set="matrix_result" t-value="prepare_result(question, current_filters)" />
<t t-set="matrix_result" t-value="prepare_result"/>
<!-- Tabs -->
<ul class="nav nav-tabs">
<ul class="nav nav-tabs hidden-print">
<li class="active">
<a t-att-href="'#graph_question_'+str(question.id)" data-toggle="tab">
<a t-att-href="'#graph_question_%d' % question.id" data-toggle="tab">
<i class="fa fa-bar-chart-o"></i>
Graph
</a>
</li>
<li>
<a t-att-href="'#data_question_'+str(question.id)" data-toggle="tab">
<a t-att-href="'#data_question_%d' % question.id" data-toggle="tab">
<i class="fa fa-list-alt"></i>
Data
</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active with-3d-shadow with-transitions survey_graph" t-att-id="'graph_question_'+str(question.id)" t-att-data-question_id= "question.id" data-graph_type= "multi_bar" t-att-data-current_filters="current_filters">
<div class="tab-pane active with-3d-shadow with-transitions survey_graph" t-att-id="'graph_question_%d' % question.id" t-att-data-question_id= "question.id" data-graph_type= "multi_bar" t-att-graph-data="graph_data">
<!-- svg element for drawing Multibar chart -->
<svg style="height:20em"></svg>
</div>
<div class="tab-pane" t-att-id="'data_question_'+str(question.id)">
<table class="table table-hover text-right">
<div class="tab-pane" t-att-id="'data_question_%d' % question.id">
<table class="table table-hover table-condensed text-right">
<thead>
<tr>
<th></th>
@ -206,30 +222,30 @@
<!-- Result for Numeric Data -->
<template id="result_number" name="Number Result">
<t t-set="number_result" t-value="prepare_result(question, current_filters)" />
<t t-set="number_result" t-value="prepare_result"/>
<t t-set="text_result" t-value="number_result['input_lines']" />
<span class="pull-right mt8">
<span class="label label-default only_left_radius">Maximum </span> <span class="label label-success only_right_radius" t-esc="number_result['max']"></span>
<span class="label label-default only_left_radius">Minimum </span> <span class="label label-danger only_right_radius" t-esc="number_result['min']"></span>
<span class="label label-default only_left_radius">Average </span> <span class="label label-warning only_right_radius" t-esc="number_result['average']"></span>
</span>
<ul class="nav nav-tabs">
<ul class="nav nav-tabs hidden-print">
<li class="active">
<a t-att-href="'#most_common_'+str(question.id)" data-toggle="tab">
<a t-att-href="'#most_common_%d' % question.id" data-toggle="tab">
<i class="fa fa-list-ol"></i>
Most Common <span t-esc="len(number_result['most_comman'])"></span>
</a>
</li>
<li>
<a t-att-href="'#data_question_'+str(question.id)" data-toggle="tab">
<a t-att-href="'#data_question_%d' % question.id" data-toggle="tab">
<i class="fa fa-list-alt"></i>
All Data
</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active with-3d-shadow with-transitions" t-att-id="'most_common_'+str(question.id)">
<table class="table table-hover">
<div class="tab-pane active with-3d-shadow with-transitions" t-att-id="'most_common_%d' % question.id">
<table class="table table-hover table-condensed">
<thead>
<tr>
<th>User Responce</th>
@ -248,8 +264,8 @@
</tbody>
</table>
</div>
<div class="tab-pane" t-att-id="'data_question_'+str(question.id)">
<table class="table table-hover" t-att-id="'table_question_'+str(question.id)">
<div class="tab-pane" t-att-id="'data_question_%d' % question.id">
<table class="table table-hover table-condensed" t-att-id="'table_question_%d' % question.id">
<thead>
<tr>
<th>#</th>
@ -287,7 +303,7 @@
</template>
<!-- Pagination Element -->
<template id="pagination" name="Survey Result">
<t t-set="record_limit" t-value="5"/><!-- Change This record_limit to change number of record per page-->
<t t-set="record_limit" t-value="10"/><!-- Change This record_limit to change number of record per page-->
<ul t-att-id="'pagination_%d' % question.id" class="pagination" t-att-data-question_id="question.id" t-att-data-record_limit="record_limit">
<t t-if="len(text_result) > record_limit">
<li t-foreach="page_range(len(text_result), record_limit)" t-as="num">