19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:30:27 +01:00
parent d1963a3c3a
commit 2d3ee4855a
7430 changed files with 2687981 additions and 2965473 deletions

View file

@ -4,7 +4,7 @@
<record id="res_partner_action_certifications" model="ir.actions.act_window">
<field name="name">Certifications Succeeded</field>
<field name="res_model">survey.user_input</field>
<field name="view_mode">tree,form</field>
<field name="view_mode">list,form</field>
<field name="context">{'search_default_scoring_success': 1}</field>
</record>
@ -17,21 +17,21 @@
<button class="oe_stat_button" type="object"
icon="fa-trophy" name="action_view_certifications"
groups="survey.group_survey_user"
attrs="{'invisible': ['|', ('certifications_count', '=', 0), ('is_company', '=', True)]}">
invisible="certifications_count == 0 or is_company">
<div class="o_field_widget o_stat_info">
<span class="o_stat_value"><field name="certifications_count" /></span>
<span class="o_stat_text" attrs="{'invisible': [('certifications_count', '&lt;', 2)]}">Certifications</span>
<span class="o_stat_text" attrs="{'invisible': [('certifications_count', '&gt;', 1)]}">Certification</span>
<span class="o_stat_text" invisible="certifications_count &lt; 2">Certifications</span>
<span class="o_stat_text" invisible="certifications_count &gt; 1">Certification</span>
</div>
</button>
<button class="oe_stat_button" type="object"
icon="fa-trophy" name="action_view_certifications"
groups="survey.group_survey_user"
attrs="{'invisible': ['|', ('certifications_company_count', '=', 0), ('is_company', '=', False)]}">
invisible="certifications_company_count == 0 or not is_company">
<div class="o_field_widget o_stat_info">
<span class="o_stat_value"><field name="certifications_company_count" /></span>
<span class="o_stat_text" attrs="{'invisible': [('certifications_company_count', '&lt;', 2)]}">Certifications</span>
<span class="o_stat_text" attrs="{'invisible': [('certifications_company_count', '&gt;', 1)]}">Certification</span>
<span class="o_stat_text" invisible="certifications_company_count &lt; 2">Certifications</span>
<span class="o_stat_text" invisible="certifications_company_count &gt; 1">Certification</span>
</div>
</button>
</xpath>

View file

@ -6,7 +6,7 @@
id="menu_surveys"
sequence="130"
groups="group_survey_user"
web_icon="survey,static/description/icon.svg"/>
web_icon="survey,static/description/icon.png"/>
<!-- Parent menus -->
<menuitem name="Questions &amp; Answers"

View file

@ -7,33 +7,38 @@
<field name="model">survey.question</field>
<field name="arch" type="xml">
<form string="Survey Question" create="false" class="o_survey_question_view_form">
<field name="is_placed_before_trigger" invisible="1"/>
<div class="alert alert-warning text-center" role="alert" invisible="not is_placed_before_trigger">
⚠️ This question is positioned before some or all of its triggers and could be skipped.
</div>
<field name="is_page" invisible="1"/>
<field name="page_id" invisible="1" required="False"/>
<field name="survey_id" invisible="1"/>
<field name="sequence" invisible="1"/>
<field name="scoring_type" invisible="1"/>
<field name="has_image_only_suggested_answer" invisible="1"/>
<sheet>
<div class="float-end d-flex flex-column text-center" attrs="{'invisible': [('is_page', '=', False)]}">
<field name="survey_id" invisible="not context.get('show_survey_field')" readonly="1"/>
<div class="float-end d-flex flex-column text-center" invisible="not is_page">
<label for="background_image"/>
<field name="background_image" widget="image" class="oe_avatar"/>
</div>
<div class="oe_title" style="width: 100%;">
<label for="title" string="Section" attrs="{'invisible': [('is_page', '=', False)]}"/>
<label for="title" string="Question" attrs="{'invisible': [('is_page', '=', True)]}"/>
<label for="title" string="Section" invisible="not is_page"/>
<label for="title" string="Question" invisible="is_page"/><br/>
<field name="title" placeholder="e.g. &quot;What is the...&quot;" colspan="4"/>
<field name="questions_selection" invisible="1"/>
</div>
<group class="o_label_nowrap" attrs="{'invisible': ['|', ('is_page', '=', False), ('questions_selection', '=', 'all')]}">
<group class="o_label_nowrap" invisible="not is_page or questions_selection == 'all'">
<field name="random_questions_count"/>
</group>
<group attrs="{'invisible': [('is_page', '=', True)]}">
<group invisible="is_page">
<group>
<field name="question_type" widget="radio" attrs="{'required': [('is_page', '=', False)]}" />
<field name="question_type" widget="radio" required="not is_page" />
</group>
<group>
<div class="mx-lg-auto w-lg-50 d-none d-sm-block o_preview_questions" colspan="2">
<div class="mx-lg-auto w-lg-50 d-none d-sm-block o_preview_questions bg-light" colspan="2">
<!-- Multiple choice: only one answer -->
<div attrs="{'invisible': [('question_type', '!=', 'simple_choice')]}" role="img" aria-label="Multiple choice with one answer"
<div invisible="question_type != 'simple_choice'" role="img" aria-label="Multiple choice with one answer"
title="Multiple choice with one answer">
<span>Which is yellow?</span><br/>
<div class="o_preview_questions_choice mb-2"><i class="fa fa-circle-o fa-lg me-2"/>answer</div>
@ -41,45 +46,45 @@
<div class="o_preview_questions_choice"><i class="fa fa-circle-o fa-lg me-2"/>answer</div>
</div>
<!-- Multiple choice: multiple answers allowed -->
<div attrs="{'invisible': [('question_type', '!=', 'multiple_choice')]}" role="img" aria-label="Multiple choice with multiple answers"
<div invisible="question_type != 'multiple_choice'" role="img" aria-label="Multiple choice with multiple answers"
title="Multiple choice with multiple answers">
<span>Which are yellow?</span><br/>
<div class="o_preview_questions_choice mb-2"><i class="fa fa-square-o fa-lg me-2"/>answer</div>
<div class="o_preview_questions_choice mb-2"><i class="fa fa-check-square-o fa-lg me-2"/>answer</div>
<div class="o_preview_questions_choice"><i class="fa fa-square-o fa-lg me-2"/>answer</div>
<div class="o_preview_questions_choice"><i class="fa fa-check-square-o fa-lg me-2"/>answer</div>
</div>
<!-- Multiple Lines Text Zone -->
<div attrs="{'invisible': [('question_type', '!=', 'text_box')]}">
<div invisible="question_type != 'text_box'">
<span>Name all the animals</span><br/>
<i class="fa fa-align-justify fa-4x" role="img" aria-label="Multiple lines" title="Multiple Lines"/>
</div>
<!-- Single Line Text Zone -->
<div attrs="{'invisible': [('question_type', '!=', 'char_box')]}">
<div invisible="question_type != 'char_box'">
<span>Name one animal</span><br/>
<i class="fa fa-minus fa-4x" role="img" aria-label="Single Line" title="Single Line"/>
</div>
<!-- Numerical Value -->
<div attrs="{'invisible': [('question_type', '!=', 'numerical_box')]}">
<div invisible="question_type != 'numerical_box'">
<span>How many ...?</span><br/>
<i class="fa fa-2x" role="img" aria-label="Numeric" title="Numeric">123&#160;</i>
<i class="fa fa-2x fa-sort" role="img" aria-label="Numeric"/>
</div>
<!-- Date -->
<div attrs="{'invisible': [('question_type', '!=', 'date')]}">
<div invisible="question_type != 'date'">
<span>When is Christmas?</span><br/>
<p class="o_datetime border-0" >YYYY-MM-DD
<i class="fa fa-calendar" role="img" aria-label="Calendar" title="Calendar"/>
</p>
</div>
<!-- Date and Time -->
<div attrs="{'invisible': [('question_type', '!=', 'datetime')]}">
<div invisible="question_type != 'datetime'">
<span>When does ... start?</span><br/>
<p class="o_datetime border-0">YYYY-MM-DD hh:mm:ss
<i class="fa fa-calendar" role="img" aria-label="Calendar" title="Calendar"/>
</p>
</div>
<!-- Matrix -->
<div attrs="{'invisible': [('question_type', '!=', 'matrix')]}">
<div invisible="question_type != 'matrix'">
<div class="row o_matrix_head">
<div class="col-3"></div>
<div class="col-3">ans</div>
@ -105,127 +110,174 @@
<div class="col-3"><i class="fa fa-circle-o fa-lg" role="img" aria-label="Not checked" title="Not checked"/></div>
</div>
</div>
<!-- Scale -->
<div invisible="question_type != 'scale'">
<span>Do you like it?</span><br/>
<div class="btn-group w-100" role="group" aria-label="Scale">
<a role="button" type="button" class="btn btn-secondary disabled o_preview_questions_choice">1</a>
<a role="button" type="button" class="btn btn-secondary disabled o_preview_questions_choice">2</a>
<a role="button" type="button" class="btn btn-secondary disabled o_preview_questions_choice">3</a>
</div>
<div class="d-flex justify-content-between">
<div>Label</div>
<div>Label</div>
<div>Label</div>
</div>
</div>
</div>
</group>
</group>
<notebook>
<page string="Answers" name="answers" attrs="{'invisible': ['|', '|',
('is_page', '=', True), ('question_type', '=', 'text_box'),
'&amp;', ('scoring_type', '=', 'no_scoring'), ('question_type', 'in', ['numerical_box', 'date', 'datetime']),
]}">
<page string="Answers" name="answers" invisible="is_page or question_type == 'text_box' or scoring_type == 'no_scoring' and question_type in ['numerical_box', 'date', 'datetime']">
<group>
<group attrs="{'invisible': [('question_type', 'not in', ['char_box', 'numerical_box', 'date', 'datetime'])]}">
<field name="answer_numerical_box" string="Correct Answer"
attrs="{'invisible': [('question_type', '!=', 'numerical_box')], 'required': [('is_scored_question', '=', True), ('question_type', '=', 'numerical_box')]}" class="oe_inline"/>
<field name="answer_date" string="Correct Answer"
attrs="{'invisible': [('question_type', '!=', 'date')], 'required': [('is_scored_question', '=', True), ('question_type', '=', 'date')]}" class="oe_inline"/>
<field name="answer_datetime" string="Correct Answer"
attrs="{'invisible': [('question_type', '!=', 'datetime')], 'required': [('is_scored_question', '=', True), ('question_type', '=', 'datetime')]}" class="oe_inline"/>
<group invisible="question_type != 'scale'">
<field name="scale_min" placeholder="Scale Minimum Value (0 to 10)"/>
<field name="scale_max" placeholder="Scale Maximum Value (0 to 10)"/>
</group>
<group invisible="question_type != 'scale'">
<field name="scale_min_label" placeholder="Not likely at all"/>
<field name="scale_mid_label" placeholder="Neutral"/>
<field name="scale_max_label" placeholder="Extremely likely"/>
</group>
<group invisible="question_type not in ['char_box', 'numerical_box', 'date', 'datetime']">
<field name="answer_numerical_box" string="Correct Answer" class="oe_inline"
invisible="question_type != 'numerical_box'"
required="is_scored_question and question_type == 'numerical_box'" />
<field name="answer_date" string="Correct Answer" class="oe_inline"
invisible="question_type != 'date'"
required="is_scored_question and question_type == 'date'"/>
<field name="answer_datetime" string="Correct Answer" class="oe_inline"
invisible="question_type != 'datetime'"
required="is_scored_question and question_type == 'datetime'"/>
<field name="validation_email" attrs="{'invisible': [('question_type', '!=', 'char_box')]}"/>
<field name="save_as_email" attrs="{'invisible': ['|', ('validation_email', '=', False), ('question_type', '!=', 'char_box')]}"/>
<field name="save_as_nickname" attrs="{'invisible': [('question_type', '!=', 'char_box')]}"/>
<field name="validation_email" invisible="question_type != 'char_box'"/>
<field name="save_as_email" invisible="not validation_email or question_type != 'char_box'"/>
<field name="save_as_nickname" invisible="question_type != 'char_box'"/>
</group>
<group attrs="{'invisible': ['|', ('scoring_type', '=', 'no_scoring'), ('question_type', 'not in', ['numerical_box', 'date', 'datetime'])]}">
<group invisible="scoring_type == 'no_scoring' or question_type not in ['numerical_box', 'date', 'datetime']">
<label for="is_scored_question"/>
<div name="survey_scored_question">
<field name="is_scored_question" nolabel="1"/>
<field name="answer_score" class="w-50 mx-2" attrs="{'invisible': [('is_scored_question', '=', False)]}" nolabel="1"/>
<span attrs="{'invisible': [('is_scored_question', '!=', True)]}">Points</span>
<field name="answer_score" class="w-50 mx-2" invisible="not is_scored_question" nolabel="1"/>
<span invisible="not is_scored_question">Points</span>
</div>
</group>
</group>
<group attrs="{'invisible': [('question_type', 'not in', ['simple_choice', 'multiple_choice', 'matrix'])]}">
<field name="suggested_answer_ids" context="{'default_question_id': active_id}" nolabel="1" colspan="2">
<tree editable="bottom">
<field name="sequence" widget="handle"/>
<field name="value" string="Choices"/>
<field name="is_correct"
attrs="{'column_invisible': ['|', ('parent.scoring_type', '=', 'no_scoring'), ('parent.question_type', '=', 'matrix')]}"/>
<field name="answer_score"
attrs="{'column_invisible': ['|', ('parent.scoring_type', '=', 'no_scoring'), ('parent.question_type', '=', 'matrix')]}"/>
<field name="value_image_filename" invisible="1"/>
<field name="value_image" width="200px" filename="value_image_filename" options="{'accepted_file_extensions': 'image/*'}"
attrs="{'column_invisible': [('parent.question_type', '=', 'matrix')]}"/>
</tree>
</field>
</group>
<field name="suggested_answer_ids" context="{'default_question_id': id}" invisible="question_type not in ['simple_choice', 'multiple_choice', 'matrix']">
<list editable="bottom">
<field name="sequence" widget="handle"/>
<field name="value" string="Choices" required="not value_image"/>
<field name="is_correct"
column_invisible="parent.scoring_type == 'no_scoring' or parent.question_type == 'matrix'"/>
<field name="answer_score"
column_invisible="parent.scoring_type == 'no_scoring' or parent.question_type == 'matrix'"/>
<field name="value_image_filename" column_invisible="not parent.has_image_only_suggested_answer"/>
<field name="value_image" width="200px" filename="value_image_filename" options="{'accepted_file_extensions': 'image/*'}"
column_invisible="parent.question_type in ['matrix', 'scale']" required="not value"/>
</list>
</field>
<group attrs="{'invisible': [('question_type', '!=', 'matrix')]}">
<field name="matrix_row_ids" context="{'default_matrix_question_id': active_id}"
attrs="{'invisible': [('question_type', '!=', 'matrix')]}" nolabel="1" colspan="2">
<tree editable="bottom">
<field name="sequence" widget="handle"/>
<field name="value" string="Rows"/>
</tree>
</field>
</group>
<field name="matrix_row_ids" context="{'default_matrix_question_id': id}"
invisible="question_type != 'matrix'">
<list editable="bottom">
<field name="sequence" widget="handle"/>
<field name="value" string="Rows"/>
</list>
</field>
</page>
<page string="Description" name="survey_description">
<field name="description" widget="html"
options="{'embedded_components': false}"
placeholder="e.g. Guidelines, instructions, picture, ... to help attendees answer"/>
</page>
<page string="Options" name="options" attrs="{'invisible': [('is_page', '=', True)]}">
<page string="Options" name="options" invisible="is_page">
<group>
<group string="Answers">
<group string="Answers" invisible="question_type == 'scale'">
<!-- Global validation setting -->
<field name="validation_required"
attrs="{'invisible': [('question_type', 'not in', ['char_box', 'numerical_box', 'date', 'datetime'])]}"/>
<!-- Char -->
<field name="validation_length_min" attrs="{'invisible': ['|', ('question_type', '!=', 'char_box'), ('validation_required', '=', False)]}"/>
<field name="validation_length_max" attrs="{'invisible': ['|', ('question_type', '!=', 'char_box'), ('validation_required', '=', False)]}"/>
<!-- Numerical -->
<field name="validation_min_float_value"
attrs="{'invisible': ['|', ('question_type', '!=', 'numerical_box'), ('validation_required', '=', False)]}"/>
<field name="validation_max_float_value"
attrs="{'invisible': ['|', ('question_type', '!=', 'numerical_box'), ('validation_required', '=', False)]}"/>
<!-- Date and datetime -->
<field name="validation_min_date" attrs="{'invisible': ['|', ('question_type', '!=', 'date'), ('validation_required', '=', False)]}"/>
<field name="validation_max_date" attrs="{'invisible': ['|', ('question_type', '!=', 'date'), ('validation_required', '=', False)]}"/>
<field name="validation_min_datetime" widget="datetime"
attrs="{'invisible': ['|', ('question_type', '!=', 'datetime'), ('validation_required', '=', False)]}"/>
<field name="validation_max_datetime" widget="datetime"
attrs="{'invisible': ['|', ('question_type', '!=', 'datetime'), ('validation_required', '=', False)]}"/>
invisible="question_type not in ['char_box', 'numerical_box', 'date', 'datetime']"/>
<div class="o_wrap_label o_form_label" invisible="not validation_required">Min/Max Limits</div>
<div class="o_survey_question_validation_parameters" invisible="not validation_required">
<!-- Minima -->
<field name="validation_length_min" class="o_survey_question_validation_inline" nolabel="1" placeholder="Minimum"
invisible="question_type != 'char_box'"
required="validation_required and question_type == 'char_box'"/>
<field name="validation_min_float_value" class="o_survey_question_validation_inline" nolabel="1" placeholder="Minimum"
invisible="question_type != 'numerical_box'"
required="validation_required and question_type == 'numerical_box'"/>
<field name="validation_min_date" nolabel="1" placeholder="Minimum"
invisible="question_type != 'date'"
required="validation_required and question_type == 'date' and not validation_max_date"/>
<field name="validation_min_datetime" nolabel="1" placeholder="Minimum"
invisible="question_type != 'datetime'"
required="validation_required and question_type == 'datetime' and not validation_max_datetime"/>
<field name="validation_error_msg" attrs="{
'invisible': [('validation_required', '=', False)]}"
placeholder="The answer you entered is not valid."/>
<i class="fa fa-long-arrow-right mx-2" aria-label="Arrow icon" title="Arrow"/>
<!-- Maxima -->
<field name="validation_length_max" class="o_survey_question_validation_inline" nolabel="1" placeholder="Maximum"
invisible="question_type != 'char_box'"
required="validation_required and question_type == 'char_box'"/>
<field name="validation_max_float_value" class="o_survey_question_validation_inline" nolabel="1" placeholder="Maximum"
invisible="question_type != 'numerical_box'"
required="validation_required and question_type == 'numerical_box'"/>
<field name="validation_max_date" nolabel="1" placeholder="Maximum"
invisible="question_type != 'date'"
required="validation_required and question_type == 'date' and not validation_min_date"/>
<field name="validation_max_datetime" nolabel="1" placeholder="Maximum"
invisible="question_type != 'datetime'"
required="validation_required and question_type == 'datetime' and not validation_min_datetime"/>
</div>
<field name="validation_error_msg" invisible="not validation_required"
placeholder="Displayed when the answer entered is not valid."/>
<field name="matrix_subtype" attrs="{'invisible':[('question_type','not in',['matrix'])],'required':[('question_type','=','matrix')]}"/>
<field name="matrix_subtype" invisible="question_type != 'matrix'" required="question_type == 'matrix'"/>
<field name="question_placeholder"
attrs="{'invisible': [('question_type', 'not in', ['text_box', 'char_box', 'date', 'datetime', 'numerical_box'])]}"
placeholder="Help Participants know what to write"/>
<field name='comments_allowed' attrs="{'invisible':[('question_type','not in',['simple_choice','multiple_choice', 'matrix'])]}"/>
<field name='comments_message'
attrs="{'invisible': ['|', ('question_type', 'not in', ['simple_choice','multiple_choice', 'matrix']), ('comments_allowed', '=', False)]}"
placeholder="If other, please specify:"/>
invisible="question_type not in ['text_box', 'char_box', 'date', 'datetime', 'numerical_box']"
placeholder="Help Participants know what to write"/>
<field name="comments_allowed" invisible="question_type not in ['simple_choice', 'multiple_choice', 'matrix']"/>
<field name="comments_message"
invisible="question_type not in ['simple_choice', 'multiple_choice', 'matrix'] or not comments_allowed"
placeholder="If other, please specify:"/>
<field name='comment_count_as_answer'
attrs="{'invisible': ['|', ('question_type', 'not in', ['simple_choice','multiple_choice', 'matrix']), ('comments_allowed', '=', False)]}"/>
invisible="question_type not in ['simple_choice', 'multiple_choice', 'matrix'] or not comments_allowed"/>
</group>
<group string="Layout">
<field name="is_conditional" attrs="{'invisible': [('questions_selection', '=', 'random')]}"/>
<field name="triggering_question_id" options="{'no_open': True, 'no_create': True}"
attrs="{'invisible': [('is_conditional','=', False)], 'required': [('is_conditional','=', True)]}"/>
<field name="triggering_answer_id" options="{'no_open': True, 'no_create': True}"
attrs="{'invisible': ['|', ('is_conditional','=', False), ('triggering_question_id','=', False)],
'required': [('is_conditional','=', True)]}"/>
<group string="Conditional display">
<p class="text-muted" colspan="2" invisible="questions_selection == 'all'">
Conditional display is not available when questions are randomly picked.
</p>
<field name="allowed_triggering_question_ids" invisible="1"/>
<field name="triggering_answer_ids" widget="many2many_tags" options="{'no_open': True, 'no_create': True}"
domain="[('question_id', 'in', allowed_triggering_question_ids)]"
invisible="questions_selection == 'random'"
placeholder="Optional previous answers required"
/>
</group>
</group>
<group>
<group string="Constraints">
<field name="constr_mandatory" string="Mandatory Answer"/>
<field name="constr_error_msg"
attrs="{'invisible': [('constr_mandatory', '=', False)]}"
invisible="not constr_mandatory"
placeholder="This question requires an answer."/>
</group>
<group string="Live Sessions">
<label for="is_time_limited" string="Question Time Limit"/>
<div>
<field name="is_time_limited" nolabel="1"/>
<field name="is_time_customized" invisible="True"/>
<field name="session_available" invisible="True"/>
<p class="text-muted" colspan="2" invisible="session_available">
Time limits are only available for Live Sessions.
</p>
<label for="is_time_limited" string="Time Limit (seconds)" invisible="not session_available"/>
<div invisible="not session_available">
<field name="is_time_limited" nolabel="1" class="oe_inline"
widget="boolean_update_flag"
options="{'flagFieldName': 'is_time_customized'}"
context="{'referenceValue': survey_session_speed_rating}"/>
<field name="time_limit" nolabel="1" class="oe_inline"
attrs="{'invisible': [('is_time_limited', '=', False)]}" />
<span attrs="{'invisible': [('is_time_limited', '=', False)]}"> seconds</span>
widget="integer_update_flag"
options="{'flagFieldName': 'is_time_customized'}"
context="{'referenceValue': survey_session_speed_rating_time_limit}"
invisible="not is_time_limited" />
</div>
</group>
</group>
@ -236,18 +288,15 @@
</field>
</record>
<record model="ir.ui.view" id="survey_question_tree">
<field name="name">Tree view for survey question</field>
<field name="name">List view for survey question</field>
<field name="model">survey.question</field>
<field name="arch" type="xml">
<tree string="Survey Question" create="false">
<field name="sequence" widget="handle"/>
<list string="Survey Question" create="false">
<field name="title"/>
<field name="survey_id"/>
<field name="question_type"/>
<field name="triggering_question_id" invisible="1"/>
<button disabled="disabled" icon="fa-code-fork" attrs="{'invisible': [('triggering_question_id', '=', False)]}"
title="This question depends on another question's answer." class="icon_rotates"/>
</tree>
<field name="constr_mandatory" optional="1"/>
</list>
</field>
</record>
<record model="ir.ui.view" id="survey_question_search">
@ -258,7 +307,7 @@
<field name="title"/>
<field name="survey_id" string="Survey"/>
<field name="question_type" string="Type"/>
<group expand="1" string="Group By">
<group>
<filter name="group_by_type" string="Type" domain="[]" context="{'group_by':'question_type'}"/>
<filter name="group_by_survey" string="Survey" domain="[]" context="{'group_by':'survey_id'}"/>
</group>
@ -269,9 +318,9 @@
<record model="ir.actions.act_window" id="action_survey_question_form">
<field name="name">Questions</field>
<field name="res_model">survey.question</field>
<field name="view_mode">tree,form</field>
<field name="view_mode">list,form</field>
<field name="search_view_id" ref="survey_question_search"/>
<field name="context">{'search_default_group_by_page': True}</field>
<field name="context">{'search_default_group_by_page': True, 'show_survey_field': True}</field>
<field name="domain">[('is_page', '=', False)]</field>
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">
@ -284,16 +333,15 @@
<!-- LABELS -->
<record id="survey_question_answer_view_tree" model="ir.ui.view">
<field name="name">survey.question.answer.view.tree</field>
<field name="name">survey.question.answer.view.list</field>
<field name="model">survey.question.answer</field>
<field name="arch" type="xml">
<tree string="Survey Label" create="false">
<list string="Survey Label" create="false" default_order="question_id">
<field name="sequence" widget="handle"/>
<field name="question_id"/>
<field name="matrix_question_id"/>
<field name="value"/>
<field name="value" string="Answer"/>
<field name="answer_score" groups="base.group_no_one"/>
</tree>
</list>
</field>
</record>
@ -301,20 +349,20 @@
<field name="name">survey.question.answer.view.form</field>
<field name="model">survey.question.answer</field>
<field name="arch" type="xml">
<form string="Question Answer Form">
<form string="Question Answer Form" create="False">
<sheet>
<field name="question_type" invisible="1"/>
<group>
<group>
<field name="scoring_type" invisible="1"/>
<field name="question_id"/>
<field name="is_correct" attrs="{'invisible': [('scoring_type', '=', 'no_scoring')]}"/>
<field name="answer_score" attrs="{'invisible': ['|', ('scoring_type', '=', 'no_scoring'), ('question_type', '=', 'matrix')]}"/>
<field name="is_correct" invisible="scoring_type == 'no_scoring'"/>
<field name="answer_score" invisible="scoring_type == 'no_scoring' or question_type == 'matrix'"/>
<field name="value_image"/>
</group>
<group>
<field name="value"/>
<field name="matrix_question_id" attrs="{'invisible': [('question_type', '!=', 'matrix')]}"/>
<field name="matrix_question_id" invisible="question_type != 'matrix'"/>
<field name="sequence"/>
</group>
</group>
@ -329,7 +377,7 @@
<field name="arch" type="xml">
<search string="Search Label">
<field name="question_id"/>
<group expand="1" string="Group By">
<group>
<filter name="group_by_question" string="Question" domain="[]" context="{'group_by':'question_id'}"/>
</group>
</search>
@ -339,7 +387,7 @@
<record id="survey_question_answer_action" model="ir.actions.act_window">
<field name="name">Suggested Values</field>
<field name="res_model">survey.question.answer</field>
<field name="view_mode">tree,form</field>
<field name="view_mode">list,form</field>
<field name="search_view_id" ref="survey_question_answer_view_search"/>
<field name="context">{'search_default_group_by_question': True}</field>
<field name="help" type="html">

View file

@ -1,122 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="certification_report_view_modern">
<!-- Style classes to be applyed to '#o_survey_certification': [no class](purple), gold, blue -->
<div id="o_survey_certification" t-att-data-oe-model="user_input._name" t-att-data-oe-id="user_input.id" t-att-class="'article certification-wrapper modern %s' % layout_color">
<div class="certification">
<div class="certification-seal" t-if="user_input.scoring_success"/>
<div class="certification-top">
<h1><b>Certificate</b>
<br/><span t-if="user_input.scoring_success">of achievement</span>
</h1>
</div>
<div class="certification-content">
<div t-if="user_input.scoring_success">
<p>This certificate is presented to
<br/>
<t t-set="certif_style" t-value="''"/>
<t t-set="certified_name" t-value="user_input.partner_id.name or user_input.email or ''"/>
<t t-if="certified_name.isupper()">
<t t-set="certif_style" t-value="certif_style + 'font-family: certification-serif;'"/>
</t>
<t t-if="len(certified_name) > 20">
<t t-set="certif_style" t-value="certif_style + 'font-size: 40px; line-height: 4;'"/>
</t>
<span t-att-style="certif_style" class="user-name" t-esc="certified_name"/>
<br/>by <span class="certification-company" t-field="user_input.env.company.display_name"/> for successfully completing
<br/><b><span class="certification-name" t-field="user_input.survey_id.display_name"/></b>
</p>
</div>
<div t-else="" class="certification-failed">
<p>Certification Failed</p>
</div>
</div>
<div class="certification-bottom">
<div class="certification-date-wrapper">
<div class="certification-date" t-field="user_input.create_date" t-options='{"widget": "date"}'/>
<span>Date</span>
</div>
<div class="certification-company">
<span class="certification-company-logo" t-field="user_input.env.company.logo" t-options="{'widget': 'image'}" role="img"/>
</div>
</div>
<div class="certification-number" t-if="user_input.scoring_success">
Certification n°<t t-esc="str(user_input.id).rjust(10, '0')"/>
</div>
</div>
<div t-if="user_input.test_entry" class="test-entry"/>
</div>
</template>
<template id="certification_report_view_classic">
<!-- Style classes to be applyed to '#o_survey_certification': [no class](purple), gold, blue -->
<div id="o_survey_certification" t-att-data-oe-model="user_input._name" t-att-data-oe-id="user_input.id" t-att-class="'article certification-wrapper classic %s' % layout_color">
<div t-if="user_input.test_entry" class="test-entry"/>
<div class="certification">
<div class="certification-top">
<h1><b>Certificate</b>
<br/><span t-if="user_input.scoring_success">of achievement</span>
</h1>
</div>
<div class="certification-content">
<div t-if="user_input.scoring_success">
<p>This certificate is presented to
<t t-set="certif_style" t-value="''"/>
<t t-set="certified_name" t-value="user_input.partner_id.name or user_input.email or ''"/>
<t t-if="certified_name.isupper()">
<t t-set="certif_style" t-value="certif_style + 'font-family: certification-serif;'"/>
</t>
<t t-if="len(certified_name) > 35">
<t t-set="certif_style" t-value="certif_style + 'font-size: 20px; line-height: 4; font-family: certification-serif; '"/>
</t>
<t t-elif="len(certified_name) > 20">
<t t-set="certif_style" t-value="certif_style + 'font-size: 30px; line-height: 4;'"/>
</t>
<br/>
<span t-att-style="certif_style" class="user-name" t-esc="certified_name"/>
<br/>by <span class="certification-company" t-field="user_input.env.company.display_name"/>
for successfully completing
<br/><b><span class="certification-name" t-field="user_input.survey_id.display_name"/></b>
</p>
</div>
<div t-else="" class="certification-failed">
<p>Certification Failed</p>
</div>
</div>
<div class="certification-bottom">
<div class="certification-date-wrapper">
<b><div class="certification-date" t-field="user_input.create_date" t-options='{"widget": "date"}'/></b>
<span>Date</span>
</div>
<div class="certification-seal"/>
<div class="certification-company">
<span class="certification-company-logo" t-field="user_input.env.company.logo" t-options="{'widget': 'image'}" role="img"/>
</div>
<div class="certification-number" t-if="user_input.scoring_success">
Certification n°<t t-esc="str(user_input.id).rjust(10, '0')"/>
</div>
</div>
</div>
</div>
</template>
<template id="certification_report_view">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="user_input">
<t t-set="layout_values" t-value="user_input.survey_id.certification_report_layout.split('_') if user_input.survey_id.certification_report_layout else ['modern', 'purple']"/>
<t t-set="layout_template" t-value="'survey.certification_report_view_%s' % (layout_values[0])"/>
<t t-set="layout_color" t-value="layout_values[1]"/>
<t t-call="{{layout_template}}"/>
</t>
</t>
</template>
</data>
</odoo>

View file

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Paper Format -->
<record id="paperformat_survey_certification" model="report.paperformat">
<field name="name">Survey Certification</field>
<field name="default" eval="True"/>
<field name="format">A4</field>
<field name="orientation">Landscape</field>
<field name="margin_top">0</field>
<field name="margin_bottom">0</field>
<field name="margin_left">0</field>
<field name="margin_right">0</field>
<field name="header_line" eval="False"/>
<field name="header_spacing">0</field>
<field name="disable_shrinking" eval="True"/>
<field name="dpi">96</field>
</record>
<!-- QWeb Reports -->
<record id="certification_report" model="ir.actions.report">
<field name="name">Certifications</field>
<field name="model">survey.user_input</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">survey.certification_report_view</field>
<field name="report_file">survey.certification_report_view</field>
<field name="print_report_name">'Certification - %s' % (object.survey_id.display_name)</field>
<field name="attachment">'certification.pdf'</field>
<field name="binding_model_id" ref="model_survey_user_input"/>
<field name="binding_type">report</field>
<field name="paperformat_id" ref="paperformat_survey_certification"/>
</record>
</data>
</odoo>

View file

@ -9,34 +9,34 @@
<field name="id" invisible="1"/>
<field name="session_state" invisible="1"/>
<field name="question_ids" invisible="1"/>
<field name="session_available" invisible="1"/>
<header>
<button name="action_send_survey" string="Share" type="object" class="oe_highlight" attrs="{'invisible': [('active', '=', False)]}"/>
<button name="action_send_survey" string="Share" type="object" class="oe_highlight" invisible="not active"/>
<button name="action_result_survey" string="See results" type="object" class="oe_highlight"
attrs="{'invisible': [('answer_done_count', '&lt;=', 0)]}"/>
invisible="answer_done_count &lt;= 0"/>
<button name="action_start_session" string="Create Live Session" type="object" class="d-none d-sm-block"
attrs="{'invisible': ['|', ('session_state', '!=', False), '|', ('active', '=', False), ('certification', '=', True)]}" />
invisible="session_state or not active or not session_available"/>
<button name="action_open_session_manager" string="Open Session Manager" type="object" class="d-none d-sm-block"
attrs="{'invisible': [('session_state', '=', False)]}" />
invisible="not session_state" />
<button name="action_end_session" string="Close Live Session" type="object" class="d-none d-sm-block"
attrs="{'invisible': [('session_state', 'not in', ['ready', 'in_progress'])]}" />
<button name="action_test_survey" string="Test" type="object" attrs="{'invisible': ['|', ('active', '=', False), ('question_ids', '=', [])]}"/>
<button name="action_unarchive" string="Reopen" class="btn-primary" type="object" attrs="{'invisible': [('active', '=', True)]}"/>
<button name="action_print_survey" string="Print" type="object" attrs="{'invisible': [('active', '=', False)]}"/>
<button name="action_archive" string="Close" type="object" attrs="{'invisible': [('active', '=', False)]}"/>
invisible="session_state not in ['ready', 'in_progress']" />
<button name="action_test_survey" string="Test" type="object" invisible="not active or not question_ids"/>
<button name="action_unarchive" string="Reopen" class="btn-primary" type="object" invisible="active"/>
<button name="action_archive" string="Close" type="object" invisible="not active"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<button name="action_survey_user_input"
type="object"
class="oe_stat_button"
attrs="{'invisible': [('access_mode', '=', 'public')]}"
invisible="access_mode == 'public'"
icon="fa-envelope-o">
<field string="Registered" name="answer_count" widget="statinfo"/>
</button>
<button name="action_survey_user_input_certified"
type="object"
class="oe_stat_button"
attrs="{'invisible': [('certification', '=', False)]}"
invisible="not certification"
icon="fa-trophy">
<field string="Certified" name="success_count" widget="statinfo"/>
</button>
@ -44,149 +44,173 @@
type="object"
class="oe_stat_button"
icon="fa-check-square-o">
<field string="Participations" name="answer_done_count" widget="statinfo"/>
<field string="Participants" name="answer_done_count" widget="statinfo"/>
</button>
</div>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<widget name="web_ribbon" title="Archived" bg_color="text-bg-danger" invisible="active"/>
<field name="background_image" widget="image" class="oe_avatar"/>
<field name="allowed_survey_types" invisible="True"/>
<field name="survey_type" widget="radio_selection_with_filter"
options="{'horizontal': True, 'allowed_selection_field': 'allowed_survey_types'}"
class="o_field_radio" invisible="not allowed_survey_types"/>
<div class="oe_title" style="width: 100%;">
<label for="title" class="oe_edit_only" string="Survey Title" attrs="{'invisible': [('certification', '=', True)]}"/>
<label for="title" class="oe_edit_only" string="Certification Title" attrs="{'invisible': [('certification', '=', False)]}"/>
<h1>
<field name="title" placeholder="e.g. Satisfaction Survey"/>
<field name="title" options="{'line_breaks': False}" widget="text" placeholder="e.g. Satisfaction Survey"/>
</h1>
</div>
<group>
<group>
<group class="ps-md-0">
<field name="user_id" domain="[('share', '=', False)]" widget="many2one_avatar_user"/>
<field name="active" invisible="1"/>
<field name="has_conditional_questions" invisible="1"/>
<field name="lang_ids" widget="many2many_tags" placeholder="All installed languages"
options="{'no_quick_create': True, 'no_create_edit': True, 'no_open': True}"/>
</group>
<group class="ps-3 ps-md-0 ps-lg-3">
<field name="restrict_user_ids" widget="many2many_tags_avatar"/>
</group>
</group>
<notebook>
<page string="Questions" name="questions">
<field name="question_and_page_ids" nolabel="1" widget="question_page_one2many" mode="tree,kanban" context="{'default_survey_id': active_id, 'default_questions_selection': questions_selection}">
<tree decoration-bf="is_page">
<field name="question_and_page_ids" nolabel="1" widget="question_page_one2many" mode="list,kanban" context="{'default_survey_id': id}">
<list decoration-bf="is_page">
<field name="sequence" widget="handle"/>
<field name="title" widget="survey_description_page"/>
<field name="background_image" invisible="1"/>
<field name="background_image" column_invisible="True"/>
<field name="question_type" />
<field name="is_page" invisible="1"/>
<field name="questions_selection" invisible="1"/>
<field name="survey_id" invisible="1"/>
<field name="triggering_question_id" invisible="1"/>
<field name="is_time_limited" string="Time Limit" optional="hide"
column_invisible="not parent.session_available"/>
<field name="time_limit" optional="hide" invisible="not is_time_limited"
column_invisible="not parent.session_available"/>
<field name="is_time_customized" column_invisible="True"/>
<field name="constr_mandatory" optional="hide"/>
<field name="is_page" column_invisible="True"/>
<field name="questions_selection" column_invisible="True"/>
<field name="survey_id" column_invisible="True"/>
<field name="random_questions_count"
attrs="{'column_invisible': [('parent.questions_selection', '=', 'all')], 'invisible': [('is_page', '=', False)]}"/>
<button disabled="disabled" icon="fa-code-fork" attrs="{'invisible': [('triggering_question_id', '=', False)]}"
title="This question depends on another question's answer." class="icon_rotates"/>
column_invisible="parent.questions_selection == 'all'"
invisible="not is_page"/>
<field name="triggering_question_ids" column_invisible="True"/>
<field name="triggering_answer_ids" column_invisible="True" widget="many2many_tags"/> <!-- widget to fetch display_name -->
<widget name="survey_question_trigger" width="30px"/>
<button name="copy" type="object" icon="fa-clone" title="Duplicate Question"/>
<control>
<create name="add_question_control" string="Add a question"/>
<create name="add_section_control" string="Add a section" context="{'default_is_page': True, 'default_questions_selection': 'all'}"/>
</control>
</tree>
</list>
</field>
</page>
<page string="Options" name="options">
<group name="options">
<group string="Questions" name="questions">
<field name="questions_layout" widget="radio"
attrs="{'readonly': [('session_state', 'in', ['ready', 'in_progress'])]}"/>
<field name="progression_mode" widget="radio" attrs="{'invisible': [('questions_layout', '=', 'one_page')]}"/>
<field name="questions_selection" widget="radio" />
<field name="users_can_go_back" string="Back Button" attrs="{'invisible': [('questions_layout', '=', 'one_page')]}"/>
<field name="questions_layout" widget="radio" force_save="1"
readonly="session_state in ['ready', 'in_progress'] or survey_type == 'live_session'"/>
<field name="progression_mode" widget="radio"
invisible="questions_layout == 'one_page' or survey_type == 'live_session'"/>
<field name="questions_selection" widget="radio"
invisible="survey_type == 'live_session'"/>
<field name="users_can_go_back" string="Allow Roaming"
invisible="questions_layout == 'one_page' or survey_type == 'live_session'"/>
</group>
<group string="Participants" name="participants">
<field name="access_mode"/>
<field name="access_mode" force_save="1"
readonly="survey_type == 'live_session'"/>
<field name="users_login_required"/>
<label for="is_attempts_limited" string="Limit Attempts"
attrs="{'invisible': ['&amp;', ('access_mode', '=', 'public'), ('users_login_required', '=', False)]}"/>
invisible="survey_type == 'live_session' or access_mode == 'public' and not users_login_required"/>
<div class="o_checkbox_optional_field"
attrs="{'invisible': ['&amp;', ('access_mode', '=', 'public'), ('users_login_required', '=', False)]}">
invisible="survey_type == 'live_session' or access_mode == 'public' and not users_login_required">
<field name="is_attempts_limited" nolabel="1"/>
<div attrs="{'invisible': [('is_attempts_limited', '=', False)]}">
<div invisible="not is_attempts_limited">
to <field name="attempts_limit" nolabel="1" class="oe_inline"/> attempts
</div>
</div>
</group>
<group string="Time &amp; Scoring" name="scoring">
<label for="is_time_limited" string="Survey Time Limit"/>
<div class="o_checkbox_optional_field">
<group string="Time &amp; Scoring" name="scoring" invisible="survey_type == 'survey'">
<!-- Time -->
<label for="is_time_limited" string="Survey Time Limit"
invisible="survey_type == 'live_session'"/>
<div class="o_checkbox_optional_field" name="is_time_limited"
invisible="survey_type == 'live_session'">
<field name="is_time_limited" nolabel="1"/>
<div attrs="{'invisible': [('is_time_limited', '=', False)]}">
<div invisible="not is_time_limited">
<field name="time_limit" widget="float_time" nolabel="1" class="oe_inline"/> minutes
</div>
</div>
<field name="scoring_type" widget="radio" />
<field name="scoring_success_min" attrs="{'invisible': [('scoring_type', '=', 'no_scoring')]}" />
<label for="certification" attrs="{'invisible': [('scoring_type', '=', 'no_scoring')]}"/>
<div class="o_checkbox_optional_field">
<field name="certification" attrs="{'invisible': [('scoring_type', '=', 'no_scoring')]}"/>
<div attrs="{'invisible': [('certification', '=', False)]}" class="w-100">
</div>
<!-- Scoring -->
<field name="scoring_type" widget="radio" force_save="1"/>
<field name="scoring_success_min" invisible="scoring_type == 'no_scoring'" />
<label for="certification"
invisible="survey_type == 'live_session' or scoring_type == 'no_scoring'"/>
<div class="o_checkbox_optional_field" name="certification"
invisible="survey_type == 'live_session'">
<field name="certification" invisible="scoring_type == 'no_scoring'"/>
<div invisible="not certification" class="w-100">
<field name="certification_report_layout" placeholder="Pick a Style..." class="w-50"/>
<button name="action_survey_preview_certification_template"
string="Preview" type="object"
icon="fa-external-link" target="_blank" class="btn-link pt-0"/>
</div>
</div>
</div>
<field name="certification_mail_template_id"
placeholder="Pick a Template..."
attrs="{'invisible': [('certification', '=', False)]}"/>
invisible="not certification"/>
<label for="certification_give_badge"
attrs="{'invisible': ['|', ('certification', '=', False), ('users_login_required', '=', False)]}"/>
invisible="not certification or not users_login_required"/>
<div class="float-start o_checkbox_optional_field"
attrs="{'invisible': ['|', ('certification', '=', False), ('users_login_required', '=', False)]}">
invisible="not certification or not users_login_required">
<field name="certification_give_badge"/>
<div attrs="{'invisible': [('certification_give_badge', '=', False)]}">
<div invisible="not certification_give_badge">
<field name="certification_badge_id"
placeholder="Pick a Badge..."
attrs="{'invisible': ['|', ('certification_give_badge', '=', False), ('certification_badge_id', '!=', False)], 'required': [('certification_give_badge', '=', True)]}"
domain="[('survey_id', '=', active_id), ('survey_id', '!=', False)]"
invisible="not certification_give_badge or certification_badge_id"
required="certification_give_badge"
domain="[('survey_id', '=', id), ('survey_id', '!=', False)]"
context="{'default_name': title,
'default_description': 'Congratulations, you have succeeded this certification',
'default_rule_auth': 'nobody',
'default_level': None,
'form_view_ref': 'survey.gamification_badge_form_view_simplified'}"/>
<field name="certification_badge_id_dummy" attrs="{'invisible': ['|', ('certification_give_badge', '=', False), ('certification_badge_id', '=', False)]}"
<field name="certification_badge_id_dummy" invisible="not certification_give_badge or not certification_badge_id"
placeholder="Pick a Badge..."
options="{'no_create': True}"
context="{'form_view_ref': 'survey.gamification_badge_form_view_simplified'}"/>
</div>
</div>
</group>
<group string="Live Session">
<group string="Live Session" name="live_session" invisible="not session_available">
<field name="access_token" invisible="1"/> <!-- dependency of 'session_code' -->
<field name="session_code" />
<field name="session_link" widget="CopyClipboardChar" />
<field name="session_speed_rating" />
<field name="session_speed_rating" invisible="scoring_type == 'no_scoring'" />
<field name="session_speed_rating_time_limit" invisible="scoring_type == 'no_scoring' or not session_speed_rating" />
</group>
</group>
</page>
<page string="Description" name="description">
<field name="description" placeholder="e.g. &quot;The following Survey will help us...&quot;" nolabel="1"></field>
<field name="description" placeholder="e.g. &quot;The following Survey will help us...&quot;" options="{'embedded_components': false}" nolabel="1"></field>
</page>
<page string="End Message" name="description_done">
<field name="description_done" placeholder="e.g. &quot;Thank you very much for your feedback!&quot;" nolabel="1"></field>
<field name="description_done" placeholder="e.g. &quot;Thank you very much for your feedback!&quot;" options="{'embedded_components': false}" nolabel="1"></field>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="activity_ids"/>
<field name="message_ids"/>
</div>
<chatter/>
</form>
</field>
</record>
<record id="survey_survey_view_tree" model="ir.ui.view">
<field name="name">survey.survey.view.tree</field>
<field name="name">survey.survey.view.list</field>
<field name="model">survey.survey</field>
<field name="arch" type="xml">
<tree string="Survey" js_class="survey_view_tree">
<field name="active" invisible="1"/>
<field name="certification" invisible="1"/>
<list string="Survey" js_class="survey_view_tree">
<field name="active" column_invisible="True"/>
<field name="certification" column_invisible="True"/>
<field name="title"/>
<button name="certification" type="button" disabled="disabled"
icon="fa-trophy" title="Certification" aria-label="Certification"
attrs="{'invisible': [('certification', '=', False)]}"/>
invisible="not certification"/>
<field name="user_id" widget="many2one_avatar_user"/>
<field name="answer_duration_avg" widget="float_time"/>
<field name="answer_count"/>
@ -195,53 +219,56 @@
<field name="success_ratio"/>
<field name="answer_score_avg"/>
<!-- Tweak as icons aren't directly supported in xml -->
</tree>
</list>
</field>
</record>
<record id="survey_survey_view_kanban" model="ir.ui.view">
<field name="name">survey.survey.view.kanban</field>
<field name="model">survey.survey</field>
<field name="arch" type="xml">
<kanban class="o_survey_survey_view_kanban" js_class="survey_view_kanban">
<kanban highlight_color="color" js_class="survey_view_kanban">
<field name="active"/>
<field name="certification"/>
<field name="color"/>
<field name="create_date"/>
<field name="scoring_type"/>
<field name="session_state"/>
<field name="success_ratio"/>
<field name="session_available"/>
<templates>
<div t-name="kanban-box"
t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)}
oe_kanban_card oe_kanban_global_click
o_survey_kanban_card #{record.certification.raw_value ? 'o_survey_kanban_card_certification' : ''}">
<!-- displayed in ungrouped mode -->
<div class="o_survey_kanban_card_ungrouped row mx-0">
<div class="col-lg-2 col-sm-8 py-0 my-2 my-lg-0 col-12">
<div t-name="menu" t-if="widget.editable">
<a role="menuitem" type="open" class="dropdown-item">Edit Survey</a>
<a t-if="record.active.raw_value" role="menuitem" type="object" class="dropdown-item" name="action_send_survey">Share</a>
<a t-if="widget.deletable" role="menuitem" type="delete" class="dropdown-item">Delete</a>
<div role="separator" class="dropdown-divider"/>
<div role="separator" class="dropdown-item-text">Color</div>
<field name="color" widget="kanban_color_picker"/>
</div>
<div t-name="card"
t-attf-class="o_survey_kanban_card #{record.certification.raw_value ? 'o_survey_kanban_card_certification' : ''}" class="px-0">
<div class="row mx-4">
<widget name="web_ribbon" title="Archived" bg_color="text-bg-danger" invisible="active"/>
<div class="col-lg-2 col-sm-8 py-0 my-2 my-lg-0 col-12 g-0">
<div class="d-flex flex-grow-1 flex-column my-0 my-lg-2">
<span class="fw-bold"><field name="title"/></span>
<span t-if="!selection_mode">
<field name="title" class="fw-bold"/>
<span t-if="!selection_mode" class="d-flex align-items-center">
<field name="user_id" widget="many2one_avatar_user"
options="{'display_avatar_name': True}"/>
-
<span class="mx-1">-</span>
<t t-esc="luxon.DateTime.fromISO(record.create_date.raw_value).toFormat('MMM yyyy')"/>
</span>
</div>
</div>
<div t-attf-class="col-lg-1 col-sm-4 d-none d-sm-block py-0 my-2 col-#{selection_mode ? '12' : '6'}">
<span class="fw-bold"><field name="question_count"/></span><br t-if="!selection_mode"/>
<div t-attf-class="col-lg-1 col-sm-4 d-sm-block py-0 my-2 col-#{selection_mode ? '12' : '6'}">
<field name="question_count" class="fw-bold"/><br t-if="!selection_mode"/>
<span class="text-muted">Questions</span>
</div>
<div t-if="selection_mode" class="col-12 d-flex justify-content-end">
<field name="user_id" widget="many2one_avatar_user"/>
</div>
<div t-if="!selection_mode" class="col-lg-1 col-sm-4 col-6 py-0 my-2">
<span class="fw-bold">
<field name="answer_duration_avg" widget="float_time"/>
</span><br />
<div t-if="!selection_mode" class="col-lg-1 col-sm-4 col-6 d-none py-0 my-2">
<field name="answer_duration_avg" widget="float_time" class="fw-bold"/>
<span class="text-muted">Average Duration</span>
</div>
<div t-if="!selection_mode" class="col-lg-1 col-sm-4 col-6 py-0 my-2">
<div t-if="!selection_mode" class="col-lg-1 col-sm-4 col-6 d-none py-0 my-2">
<a type="object"
name="action_survey_user_input"
class="fw-bold">
@ -249,7 +276,7 @@
<span class="text-muted">Registered</span>
</a>
</div>
<div t-if="!selection_mode" class="col-lg-1 col-sm-4 col-6 d-none d-sm-block py-0 my-2">
<div t-if="!selection_mode" class="col-lg-1 col-sm-4 col-6 d-sm-block py-0 my-2">
<a type="object"
name="action_survey_user_input_completed"
class="fw-bold">
@ -263,97 +290,43 @@
type="object"
name="action_survey_user_input_certified"
class="fw-bold">
<field name="success_ratio" widget="progressbar" class="d-block"/>
<field name="success_ratio" widget="progressbar" class="d-block" style="word-break: normal;"/>
<span class="text-muted" t-if="!record.certification.raw_value">Passed</span>
<span class="text-muted" t-else="">Certified</span>
</a>
</div>
<div t-if="!selection_mode" class="col-lg-3 col-sm-12 d-none d-sm-block py-0 my-2 pb-lg-3 ms-auto text-lg-end">
<div t-if="!selection_mode" class="col-lg-3 col-sm-12 d-none d-sm-flex justify-content-end gap-1 my-2 ms-auto pb-lg-3 py-0">
<button name="action_send_survey"
string="Share" type="object"
class="btn btn-secondary border"
attrs="{'invisible': [('active', '=', False)]}">
class="btn btn-secondary text-nowrap"
invisible="not active">
Share
</button>
<button name="action_test_survey"
string="Test" type="object"
class="btn btn-secondary border"
attrs="{'invisible': [('active', '=', False)]}">
class="btn btn-secondary text-nowrap"
invisible="not active">
Test
</button>
<button name="action_result_survey"
string="See results" type="object"
class="btn btn-secondary border"
attrs="{'invisible': [('active', '=', False)]}">
class="btn btn-secondary"
invisible="not active">
See results
</button>
<button name="action_start_session"
string="Start Live Session" type="object"
class="btn btn-secondary border"
attrs="{'invisible': ['|', '|', ('session_state', '!=', False), ('certification', '=', True), ('active', '=', False)]}">
class="btn btn-secondary"
invisible="session_state or not active or not session_available">
Start Live Session
</button>
<button name="action_end_session"
string="End Live Session" type="object"
class="btn btn-secondary border"
attrs="{'invisible': ['|', ('session_state', 'not in', ['ready', 'in_progress']), ('active', '=', False)]}">
class="btn btn-secondary"
invisible="session_state not in ['ready', 'in_progress'] or not active">
End Live Session
</button>
</div>
<widget name="web_ribbon" title="Archived"
bg_color="bg-danger"
attrs="{'invisible': [('active', '=', True)]}"/>
</div>
<!-- displayed in grouped mode -->
<div class="o_survey_kanban_card_grouped">
<widget name="web_ribbon" title="Archived"
bg_color="bg-danger"
attrs="{'invisible': [('active', '=', True)]}"/>
<div class="o_dropdown_kanban dropdown" t-if="widget.editable">
<a href="#" role="button"
class="dropdown-toggle o-no-caret btn"
data-bs-toggle="dropdown" data-bs-display="static"
aria-label="Dropdown menu" title="Dropdown menu">
<span class="fa fa-ellipsis-v"/>
</a>
<div class="dropdown-menu" role="menu">
<a role="menuitem" type="edit" class="dropdown-item">Edit Survey</a>
<a t-if="record.active.raw_value" role="menuitem" type="object" class="dropdown-item" name="action_send_survey">Share</a>
<a t-if="widget.deletable" role="menuitem" type="delete" class="dropdown-item">Delete</a>
<div role="separator" class="dropdown-divider"/>
<div role="separator" class="dropdown-item-text">Color</div>
<ul class="oe_kanban_colorpicker" data-field="color"/>
</div>
</div>
<div class="o_kanban_record_top">
<h4 class="o_kanban_record_title p-0 mb4"><field name="title" /></h4>
</div>
<div class="row g-0">
<div class="col-10 p-0 pb-1">
<div class="container o_kanban_card_content" t-if="record.answer_count.raw_value != 0">
<div class="row mt-4 ms-5">
<div class="col-4 p-0">
<a name="action_survey_user_input" type="object" class="d-flex flex-column align-items-center">
<span class="fw-bold"><field name="answer_count"/></span>
<span class="text-muted">Registered</span>
</a>
</div>
<div class="col-4 p-0 border-start">
<a name="action_survey_user_input_completed" type="object" class="d-flex flex-column align-items-center">
<span class="fw-bold"><field name="answer_done_count"/></span>
<span class="text-muted">Completed</span>
</a>
</div>
<div class="col-4 p-0 border-start" t-if="record.scoring_type.raw_value != 'no_scoring'" >
<a name="action_survey_user_input_certified" type="object" class="d-flex flex-column align-items-center">
<span class="fw-bold"> <t t-esc="Math.round(record.success_ratio.raw_value)"></t> %</span>
<span class="text-muted" >Success</span>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Generic -->
<div t-if="!selection_mode" class="o_survey_kanban_card_bottom">
@ -364,28 +337,53 @@
</kanban>
</field>
</record>
<record id="survey_survey_view_activity" model="ir.ui.view">
<field name="name">survey.survey.view.activity</field>
<field name="model">survey.survey</field>
<field name="arch" type="xml">
<activity string="Survey">
<templates>
<div t-name="activity-box" class="d-flex w-100">
<field name="user_id" widget="many2one_avatar_user"/>
<div class="flex-grow-1">
<field name="title" class="o_text_block"/>
</div>
</div>
</templates>
</activity>
</field>
</record>
<record id="survey_survey_view_search" model="ir.ui.view">
<field name="name">survey.survey.search</field>
<field name="model">survey.survey</field>
<field name="arch" type="xml">
<search string="Survey">
<field string="Survey" name="title"/>
<field string="Survey" name="title" filter_domain="['|', ('title', 'ilike', self), ('session_code', 'ilike', self)]"/>
<field string="Question &amp; Pages" name="question_and_page_ids"/>
<field name="user_id"/>
<field name="restrict_user_ids"/>
<filter string="Is a Certification" name="certification" domain="[('certification', '=', True)]"/>
<filter string="Is not a Certification" name="not_certification" domain="[('certification', '=', False)]"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
<separator/>
<filter invisible="1" string="My Activities" name="filter_activities_my"
domain="[('activity_user_id', '=', uid)]"/>
<separator invisible="1"/>
<filter invisible="1" string="Late Activities" name="activities_overdue"
domain="[('my_activity_date_deadline', '&lt;', context_today().strftime('%Y-%m-%d'))]"
help="Show all records which has next action date is before today"/>
domain="[('my_activity_date_deadline', '&lt;', 'today')]"
help="Show all records whose next activity date is past"/>
<filter invisible="1" string="Today Activities" name="activities_today"
domain="[('my_activity_date_deadline', '=', context_today().strftime('%Y-%m-%d'))]"/>
domain="[('my_activity_date_deadline', '=', 'today')]"/>
<filter invisible="1" string="Upcoming Activities" name="activities_upcoming_all"
domain="[('my_activity_date_deadline', '&gt;', context_today().strftime('%Y-%m-%d'))]"/>
<group expand="0" string="Group By">
domain="[('my_activity_date_deadline', '&gt;', 'today')]"/>
<group>
<filter string="Responsible" name="group_by_responsible"
context="{'group_by': 'user_id'}"/>
<filter name="group_by_restrict_user_ids"
context="{'group_by': 'restrict_user_ids'}"/>
</group>
</search>
</field>
@ -393,53 +391,9 @@
<record model="ir.actions.act_window" id="action_survey_form">
<field name="name">Surveys</field>
<field name="path">surveys</field>
<field name="res_model">survey.survey</field>
<field name="view_mode">kanban,tree,form,activity</field>
<field name="help" type="html">
<p>
No Survey Found
</p><p>
Ready to test? Pick a sample...
</p>
<div class="row mb-4">
<div class="col-sm-4 o_survey_sample_container" action="action_load_sample_feedback_form">
<div class="o_survey_sample_tile position-relative w-100 d-flex align-items-center justify-content-center m-auto">
<img src="/survey/static/src/img/survey_sample_feedback_form.png" class="img-fluid"/>
<div class="o_survey_sample_tile_cover o_survey_load_sample w-100 h-100 position-absolute rounded-circle text-center text-white p-3">
Gather feedbacks from your employees and customers
</div>
</div>
<div class="my-3">
<a class="o_survey_load_sample h3 text-center text-primary">Feedback Form</a>
</div>
<a class="btn btn-outline-primary o_survey_load_sample"><span>Try It</span></a>
</div>
<div class="col-sm-4 o_survey_sample_container" action="action_load_sample_certification">
<div class="o_survey_sample_tile position-relative w-100 d-flex align-items-center justify-content-center m-auto">
<img src="/survey/static/src/img/survey_sample_certification.png" class="img-fluid"/>
<div class="o_survey_sample_tile_cover o_survey_load_sample w-100 h-100 position-absolute rounded-circle text-center text-white p-3">
Handle quiz &amp; certifications
</div>
</div>
<div class="my-3">
<a class="o_survey_load_sample h3 text-center text-primary">Certification</a>
</div>
<a class="btn btn-outline-primary o_survey_load_sample"><span>Try It</span></a>
</div>
<div class="col-sm-4 o_survey_sample_container" action="action_load_sample_live_presentation">
<div class="o_survey_sample_tile position-relative w-100 d-flex align-items-center justify-content-center m-auto">
<img src="/survey/static/src/img/survey_sample_live_presentation.png" class="img-fluid"/>
<div class="o_survey_sample_tile_cover o_survey_load_sample w-100 h-100 position-absolute rounded-circle text-center text-white p-3">
Add some fun to your presentations by sharing questions live
</div>
</div>
<div class="my-3">
<a class="o_survey_load_sample h3 text-center text-primary">Live Presentation</a>
</div>
<a class="btn btn-outline-primary o_survey_load_sample"><span>Try It</span></a>
</div>
</div>
</field>
<field name="view_mode">kanban,list,form,activity</field>
</record>
<record id="survey_survey_view_graph" model="ir.ui.view">

View file

@ -3,7 +3,7 @@
<data>
<!-- Main survey layout -->
<template id="survey.layout" name="Survey Layout" inherit_id="web.frontend_layout" primary="True">
<xpath expr="//div[@id='wrapwrap']" position="before">
<xpath expr="//head" position="before">
<!--TODO DBE Fix me : If one day, there is a survey_livechat bridge module, put this in that module-->
<t t-set="no_livechat" t-value="True"/>
</xpath>
@ -14,7 +14,7 @@
else ('background-image: url(' + page.background_image_url + ');')
if page and page.background_image_url
else ('background-image: url(' + survey.background_image_url + ');')
if survey and survey.background_image_url
if survey and survey.background_image_url and not survey_data
else '')"/>
<attribute name="t-att-class"
add="(('o_survey_background o_survey_background_shadow')
@ -37,29 +37,26 @@
<xpath expr="//footer" position="after">
<div class="py-3 m-0 p-0 text-end">
<div class="o_survey_progress_wrapper d-inline-block pe-1 text-start">
<t t-call="survey.survey_progression"
t-if="survey and survey.questions_layout != 'one_page' and answer and answer.state == 'in_progress' and (not question or not question.is_page) and not survey_form_readonly">
<t t-if="survey and survey.questions_layout != 'one_page' and answer and answer.state == 'in_progress' and (not question or not question.is_page) and not survey_form_readonly">
<t t-if="survey.questions_layout == 'page_per_section'">
<t t-set="page_ids" t-value="survey.page_ids.ids"/>
<t t-set="page_number" t-value="page_ids.index(page.id) + (1 if survey.progression_mode == 'number' else 0)"/>
</t>
<t t-else="">
<t t-if="not answer.is_session_answer and survey.questions_selection == 'random'">
<t t-set="page_ids" t-value="answer.predefined_question_ids.ids"/>
</t>
<t t-else="">
<t t-set="page_ids" t-value="survey.question_ids.ids"/>
</t>
<t t-if="not answer.is_session_answer and survey.questions_selection == 'random'"
t-set="page_ids" t-value="answer.predefined_question_ids.ids"/>
<t t-else="" t-set="page_ids" t-value="survey.question_ids.ids"/>
<t t-set="page_number" t-value="page_ids.index(question.id)"/>
</t>
<t t-call="survey.survey_progression"/>
</t>
</div>
<div class="o_survey_brand_message float-end rounded me-3 border">
<div class="px-2 py-2 d-inline-block" t-call="web.brand_promotion_message">
<t t-set="_message"></t>
<t t-set="_utm_medium" t-valuef="survey"/>
<div class="px-2 py-2 d-inline-block">
<t t-call="web.brand_promotion_message" _message.f="" _utm_medium.f="survey"/>
</div>
<div class="o_survey_navigation_wrapper d-inline-block" t-call="survey.survey_navigation">
<div t-if="not no_survey_navigation" class="o_survey_navigation_wrapper d-inline-block d-print-none">
<t t-call="survey.survey_navigation"/>
</div>
</div>
</div>
@ -71,7 +68,7 @@
<t t-call="survey.layout">
<t t-if="answer.test_entry" t-call="survey.survey_button_form_view" />
<div class="wrap o_survey_wrap d-flex">
<div class="container o_survey_form d-flex flex-column mb-5">
<div class="o_container_small o_survey_form d-flex flex-column mb-5">
<t t-call="survey.survey_fill_header" />
<t t-call="survey.survey_fill_form" />
</div>
@ -80,23 +77,33 @@
</template>
<template id="survey_fill_header" name="Survey: main page header">
<div class="o_survey_nav pt16 mb-2">
<div class="container m-0 p-0">
<div class="row">
<div class="col-lg-10">
<h1 t-if="answer.state == 'new' or survey.questions_layout != 'page_per_question'"
t-esc="survey.title" class="o_survey_main_title pt-4"></h1>
</div>
<div class="o_survey_timer col-lg-2 pt-4">
<h1 class="o_survey_timer_container timer text-end">
</h1>
<div class="d-flex flex-wrap flex-md-nowrap justify-content-between pt16 mb-2">
<div t-attf-class="o_survey_nav flex-grow-1 #{'order-2 order-md-1' if languages else None}">
<div class="container m-0 p-0">
<div class="row">
<div class="col-lg-10">
<t t-set="displayTitle" t-value="answer.state == 'in_progress' and survey.questions_layout != 'page_per_question'"/>
<h1 t-out="survey.title" class="o_survey_main_title o_survey_main_title_fade pt-4"
t-attf-class="o_survey_main_title o_survey_main_title_fade pt-4 {{'opacity-0' if not displayTitle else 'opacity-100'}}"/>
</div>
<div class="o_survey_timer col-lg-2 pt-4">
<h1 class="o_survey_timer_container timer text-end"/>
</div>
</div>
</div>
<div t-att-class="'o_survey_breadcrumb_container mt8' + (' d-none ' if answer.state != 'in_progress' else '')"
t-if="not survey.has_conditional_questions and survey.questions_layout == 'page_per_section' and answer.state != 'done'"
t-att-data-can-go-back="survey.users_can_go_back"
t-att-data-pages="json.dumps(breadcrumb_pages)" />
</div>
<div t-if="languages" class="order-1 order-md-2">
<select name="lang_code"
t-attf-class="form-select o_survey_lang_selector #{'d-none' if len(languages) == 1 else ''}"
aria-label="Select a language">
<option t-foreach="languages" t-as="language" t-att-value="language[0]" t-out="language[1]"
t-att-selected="language[0] == lang_code and 'selected' or None"/>
</select>
</div>
<div t-att-class="'o_survey_breadcrumb_container mt8' + (' d-none ' if answer.state != 'in_progress' else '')"
t-if="not survey.has_conditional_questions and survey.questions_layout == 'page_per_section' and answer.state != 'done'"
t-att-data-can-go-back="survey.users_can_go_back"
t-att-data-pages="json.dumps(breadcrumb_pages)" />
</div>
</template>
@ -108,7 +115,8 @@
if page else survey.background_image_url
if survey.background_image_url else False"/>
<form role="form" method="post" t-att-name="survey.id"
class="d-flex flex-grow-1 align-items-center"
class="o_survey-fill-form d-flex flex-grow-1 align-items-center"
t-att-data-scoring-type="survey.scoring_type"
t-att-data-answer-token="answer.access_token"
t-att-data-survey-token="survey.access_token"
t-att-data-users-can-go-back="survey.users_can_go_back and not answer.is_session_answer"
@ -119,6 +127,7 @@
t-att-data-is-page-description="bool(question and question.is_page and not is_html_empty(question.description))"
t-att-data-questions-layout="survey.questions_layout"
t-att-data-triggered-questions-by-answer="json.dumps(triggered_questions_by_answer)"
t-att-data-triggering-answers-by-question="json.dumps(triggering_answers_by_question)"
t-att-data-selected-answers="json.dumps(selected_answers)"
t-att-data-refresh-background="any(page.background_image for page in survey.page_ids)">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
@ -133,26 +142,13 @@
<t t-else="" t-call="survey.survey_fill_form_done"/>
</div>
</form>
<!-- Modal used to display error message, i.c.o. ajax error -->
<div role="dialog" class="modal fade" id="MasterTabErrorModal" >
<div class="modal-dialog">
<div class="modal-content">
<header class="modal-header">
<h4 class="modal-title">A problem has occurred</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</header>
<main class="modal-body"><p>To take this survey, please close all other tabs on <strong class="text-danger"></strong>.</p></main>
<footer class="modal-footer"><button type="button" class="btn btn-primary" data-bs-dismiss="modal">Continue here</button></footer>
</div>
</div>
</div>
</template>
<template id="survey_fill_form_start" name="Survey: start form content">
<div class="wrap o_survey_start">
<div class='mb32'>
<div t-field='survey.description' class="oe_no_empty pb-5 text-break"/>
<h1 t-out="survey.title" class="o_survey_main_title pb-2"/>
<div t-field='survey.description' class="oe_no_empty pb-2 text-break"/>
<t t-if="answer.is_session_answer">
<div class="fw-bold">
The session will begin automatically when the host starts.
@ -186,20 +182,33 @@
t-att-data-has-answered="bool(has_answered)"
t-att-data-is-page-description="bool(question and question.is_page and not is_html_empty(question.description))"
t-att-data-server-time="server_time"
t-att-data-survey-last-triggering-answers="survey_last_triggering_answers"
t-att-data-timer="timer_start"
t-att-data-time-limit-minutes="time_limit_minutes"/>
<t t-if="survey.questions_layout == 'one_page'">
<t t-foreach='survey.question_and_page_ids' t-as='question'>
<h2 t-if="question.is_page" t-field='question.title' class="o_survey_title pb16 text-break" />
<div t-if="question.is_page" t-field='question.description' class="text-break"/>
<t t-if="not question.is_page and question in answer.predefined_question_ids" t-call="survey.question_container"/>
<!-- Questions without section -->
<t t-foreach="survey.question_ids.filtered(lambda q: not q.page_id)" t-as="question">
<t t-if="question in answer.predefined_question_ids" t-call="survey.question_container"/>
</t>
<!-- Questions with section -->
<t t-foreach="survey.page_ids" t-as="page">
<t t-set="display_section" t-value="page.description or any(not q.triggering_answer_ids for q in page.question_ids)
or (survey.questions_selection == 'random' and page.question_ids and page.random_questions_count > 0)"/>
<div t-attf-class="js_section_wrapper #{'d-none' if not display_section else ''}">
<h2 t-field="page.title" class="o_survey_title pb16 text-break"/>
<div t-field="page.description" class="o_survey_description text-break"/>
<t t-foreach="page.question_ids" t-as="question">
<t t-if="question in answer.predefined_question_ids" t-call="survey.question_container"/>
</t>
</div>
</t>
<div class="text-center mt16 mb256">
<button type="submit" value="finish" class="btn btn-primary disabled">Submit</button>
<span class="fw-bold text-muted ms-2 d-none d-md-inline">
<span id="enter-tooltip">or press Enter</span>
</span>
<button type="submit" value="finish" class="btn btn-secondary disabled">Submit</button>
<button id="next_page" t-attf-class="btn #{'btn-secondary' if survey_last else 'btn-primary'} d-none">Next</button>
<span class="fw-bold text-muted ms-2 d-none d-md-inline">
<span id="enter-tooltip">or press CTRL+Enter</span>
</span>
</div>
</t>
@ -214,33 +223,35 @@
<div class="row">
<div class="col-12 text-center mt16">
<button type="submit" t-att-value="'next' if not survey_last else 'finish'" class="btn btn-primary disabled">
<t t-if="not survey_last">Continue</t>
<t t-else="">Submit</t>
<t t-set="submit_value" t-value="'finish' if survey_last or answer.is_session_answer else 'next_skipped'
if answer.survey_first_submitted and skipped_questions.page_id and page in skipped_questions.page_id else 'next'"/>
<button type="submit" t-att-value="submit_value" t-attf-class="btn #{'btn-secondary' if survey_last else 'btn-primary'} disabled">
<t t-if="submit_value == 'finish'">Submit</t>
<t t-elif="submit_value == 'next_skipped'">Next Skipped</t>
<t t-else="">Continue</t>
</button>
<span class="fw-bold text-muted ms-2 d-none d-md-inline" id="enter-tooltip"> or press Enter</span>
<button id="next_page" t-attf-class="btn #{'btn-secondary' if survey_last else 'btn-primary'} d-none">Next</button>
<span class="fw-bold text-muted ms-2 d-none d-md-inline" id="enter-tooltip"> or press CTRL+Enter</span>
</div>
</div>
</t>
<!-- If we have a choice question and less than 6 options, we want minimized display.
Minimized display means we display the choices vertically (instead of optimized based on screen space).
An exception is made for options with images, where we always want to optimize screen space.
Numeric, date and datetime questions are also displayed "minimized", with a smaller screen width.-->
<t t-set="minimized_display" t-value="survey.questions_layout == 'page_per_question' and len(question.suggested_answer_ids) &lt;= 5 and not any(suggestion.value_image for suggestion in question.suggested_answer_ids)" />
<!-- Minimized display means we display the choices vertically (instead of optimized based on screen space).
An exception is made for options with images, where we always want to optimize screen space.-->
<t t-set="minimized_display" t-value="survey.questions_layout == 'page_per_question' and not any(suggestion.value_image for suggestion in question.suggested_answer_ids)" />
<div t-if="survey.questions_layout == 'page_per_question'"
t-attf-class="o_survey_page_per_question o_survey_#{question.question_type} #{'o_survey_minimized_display' if minimized_display else ''}">
t-attf-class="o_survey_page_per_question">
<input type="hidden" name="question_id" t-att-value="question.id" />
<!-- User has already answered for this session -->
<t t-if="answer.is_session_answer and (has_answered or answer.question_time_limit_reached)">
<div t-if="answer.question_time_limit_reached and not has_answered" class="fw-bold">Sorry, you have not been fast enough.</div>
<div t-else="" class="fw-bold">We have registered your answer! Please wait for the host to go to the next question.</div>
<fieldset disabled="disabled">
<t t-set="survey_form_readonly" t-value="True" />
<div class="mt-5">
<t t-call="survey.question_container" />
</div>
</fieldset>
<div t-if="answer.question_time_limit_reached and not has_answered" class="fw-bold">Sorry, you have not been fast enough.</div>
<div t-else="" class="fw-bold">We have registered your answer! Please wait for the host to go to the next question.</div>
</t>
<t t-elif="answer.is_session_answer and question.is_page and not is_html_empty(question.description)">
<div class="fw-bold mt-5">Pay attention to the host screen until the next question.</div>
@ -252,10 +263,14 @@
<div class="row">
<div class="col-12 text-center mt16">
<button type="submit" t-att-value="'next' if not survey_last else 'finish'" class="btn btn-primary disabled">
<t t-if="answer.is_session_answer or survey_last">Submit</t>
<t t-set="submit_value" t-value="'finish' if survey_last or answer.is_session_answer else
'next_skipped' if answer.survey_first_submitted and skipped_questions and question in skipped_questions else 'next'"/>
<button type="submit" t-att-value="submit_value" t-attf-class="btn #{'btn-secondary' if survey_last else 'btn-primary'} disabled">
<t t-if="submit_value == 'finish'">Submit</t>
<t t-elif="submit_value == 'next_skipped'">Next Skipped</t>
<t t-else="">Continue</t>
</button>
<button id="next_page" t-attf-class="btn #{'btn-secondary' if survey_last else 'btn-primary'} d-none">Next</button>
<span class="fw-bold text-muted ms-2 d-none d-md-inline">
<span id="enter-tooltip">or press Enter</span>
</span>
@ -269,12 +284,17 @@
<template id="survey_fill_form_done" name="Survey: finished">
<div class="wrap">
<div class="o_survey_finished mt32 mb32">
<h1>Thank you!</h1>
<h1 t-out="survey.title" class="o_survey_main_title pb-2"/>
<h1 class="fs-2">
<t t-if="survey.scoring_type != 'no_scoring'">
You scored <t t-out="answer.scoring_percentage"/>%
</t>
<t t-else="">Thank you!</t>
</h1>
<div t-field="survey.description_done" class="oe_no_empty" />
<div class="row">
<div class="col">
<t t-if="survey.scoring_type != 'no_scoring' and survey.scoring_success_min">
<div>You scored <t t-esc="answer.scoring_percentage" />%</div>
<t t-if="answer.scoring_success">
<div>Congratulations, you have passed the test!</div>
@ -291,9 +311,14 @@
<div>Unfortunately, you have failed the test.</div>
</t>
</t>
<t t-call="survey.survey_button_retake"/>
<div t-if="survey.scoring_type != 'scoring_without_answers'" class="o_survey_review">
If you wish, you can <a t-att-href="'/survey/print/%s?answer_token=%s&amp;review=True' % (survey.access_token, answer.access_token)">review your answers</a>
<div class="d-flex gap-3 mt-3">
<t t-call="survey.survey_button_retake"/>
<p t-if="survey.scoring_type != 'scoring_without_answers'">
<a role="button" class="o_survey_review btn btn-secondary btn-lg"
t-att-href="'/survey/print/%s?answer_token=%s&amp;review=True' % (survey.access_token, answer.access_token)">
Review your answers
</a>
</p>
</div>
</div>
<div class="col-6 text-center" t-if="survey.certification_give_badge and answer.scoring_success">
@ -302,18 +327,6 @@
</div>
</div>
</div>
<div class="o_survey_result p-4 col-12 row" t-if="graph_data">
<div t-if="survey.page_ids" class="survey_graph col-lg-6 d-none d-md-block"
data-graph-type="by_section"
t-att-data-graph-data="graph_data">
<canvas id="by_section_chart"></canvas>
</div>
<div t-attf-class="survey_graph col-lg-6 #{'offset-lg-3' if not survey.page_ids else ''}"
data-graph-type="doughnut"
t-att-data-graph-data="graph_data">
<canvas id="doughnut_chart"></canvas>
</div>
</div>
</div>
</template>
@ -322,10 +335,14 @@
<t t-set="display_question"
t-value="survey.questions_layout == 'page_per_question'
or survey.questions_selection == 'random'
or (survey.questions_layout == 'one_page' and not question.is_conditional)
or (survey.questions_layout == 'page_per_section' and (not question.is_conditional or triggering_answer_by_question[question.id] in selected_answers))"/>
or (survey.questions_layout == 'one_page' and not question.triggering_answer_ids)
or (survey.questions_layout == 'page_per_section' and (not question.triggering_answer_ids
or any(triggering_answer in selected_answers for triggering_answer in triggering_answers_by_question[question.id])))"/>
<t t-set="answer_lines" t-value="answer.user_input_line_ids.filtered(lambda line: line.question_id == question)"/>
<t t-set="answers_contain_image" t-value="any(a.value_image for a in question.suggested_answer_ids)"/>
<t t-set="use_half_columns" t-value="survey.questions_layout == 'page_per_question' and answers_contain_image"/>
<t t-set="use_half_col_lg" t-value="'col-lg-6' if (use_half_columns and not survey_form_readonly) or (answer.is_session_answer and answers_contain_image) else ''"/>
<!--Use Key selection if number of choices is < 26 to keep Z for other choice if any-->
<t t-set="letters" t-value="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<t t-set="useKeySelection" t-value="len(question.suggested_answer_ids) &lt; len(letters) and survey.questions_layout == 'page_per_question'"/>
@ -334,10 +351,14 @@
<t t-set="default_constr_error_msg">This question requires an answer.</t>
<t t-set="default_validation_error_msg">The answer you entered is not valid.</t>
<t t-set="default_comments_message">If other, please specify:</t>
<div t-att-class="'js_question-wrapper pb-4 %s %s' % ('d-none' if not display_question else '', 'me-2' if extra_right_margin else '')"
t-att-id="question.id" t-att-data-required="question.constr_mandatory"
t-att-data-constr-error-msg="question.constr_error_msg or default_constr_error_msg"
t-att-data-validation-error-msg="question.validation_error_msg or default_validation_error_msg">
<t t-set="is_skipped_question" t-value="skipped_questions and question in skipped_questions"/>
<div t-attf-class="js_question-wrapper pb-4
#{'d-none' if not display_question else ''}
#{'me-2' if extra_right_margin else ''}"
t-att-id="question.id"
t-att-data-required="bool(question.constr_mandatory and (not survey.users_can_go_back or survey.questions_layout == 'one_page')) or None"
t-att-data-constr-error-msg="question.constr_error_msg or default_constr_error_msg if question.constr_mandatory else None"
t-att-data-validation-error-msg="question.validation_error_msg or default_validation_error_msg if question.validation_required else None">
<div class="mb-4">
<h3 t-if="not hide_question_title">
<span t-field='question.title' class="text-break" />
@ -345,20 +366,24 @@
</h3>
<div t-if="not is_html_empty(question.description)" t-field='question.description' class="text-muted oe_no_empty mt-1 text-break"/>
</div>
<t t-if="question.question_type == 'text_box'"><t t-call="survey.question_text_box"/></t>
<t t-if="question.question_type == 'char_box'"><t t-call="survey.question_char_box"/></t>
<t t-if="question.question_type == 'numerical_box'"><t t-call="survey.question_numerical_box"/></t>
<t t-if="question.question_type == 'date'"><t t-call="survey.question_date"/></t>
<t t-if="question.question_type == 'datetime'"><t t-call="survey.question_datetime"/></t>
<t t-if="question.question_type == 'simple_choice'"><t t-call="survey.question_simple_choice"/></t>
<t t-if="question.question_type == 'multiple_choice'"><t t-call="survey.question_multiple_choice"/></t>
<t t-if="question.question_type == 'matrix'"><t t-call="survey.question_matrix"/></t>
<div class="o_survey_question_error overflow-hidden border-0 py-0 px-3 alert alert-danger" role="alert"></div>
<t t-if="question.question_type == 'text_box'" t-call="survey.question_text_box"/>
<t t-if="question.question_type == 'char_box'" t-call="survey.question_char_box"/>
<t t-if="question.question_type == 'numerical_box'" t-call="survey.question_numerical_box"/>
<t t-if="question.question_type == 'date'" t-call="survey.question_date"/>
<t t-if="question.question_type == 'datetime'" t-call="survey.question_datetime"/>
<t t-if="question.question_type == 'simple_choice'" t-call="survey.question_simple_choice"/>
<t t-if="question.question_type == 'scale'" t-call="survey.question_scale"/>
<t t-if="question.question_type == 'multiple_choice'" t-call="survey.question_multiple_choice"/>
<t t-if="question.question_type == 'matrix'" t-call="survey.question_matrix"/>
<div t-attf-class="o_survey_question_error d-flex align-items-center justify-content-between overflow-hidden
border-0 py-0 px-3 alert alert-danger mt-2 #{'slide_in' if is_skipped_question else ''}" role="alert">
<span t-if="is_skipped_question" t-out="question.constr_error_msg or default_constr_error_msg"/>
</div>
</div>
</template>
<template id="question_text_box" name="Question: free text box">
<div class="o_survey_comment_container p-0">
<div class="o_survey_comment_container h-auto p-0">
<textarea class="form-control o_survey_question_text_box bg-transparent rounded-0 p-0" rows="3"
t-att-name="question.id" t-att-placeholder="question.question_placeholder"
t-att-data-question-type="question.question_type"><t t-if="answer_lines" t-esc="answer_lines[0].value_text_box or None"/></textarea>
@ -378,37 +403,84 @@
</template>
<template id="question_numerical_box" name="Question: numerical box">
<input type="number" step="any" class="form-control o_survey_question_numerical_box bg-transparent rounded-0 p-0"
t-att-name="question.id" t-att-placeholder="question.question_placeholder"
t-att-value="answer_lines[0].value_numerical_box if answer_lines else None"
t-att-data-question-type="question.question_type"
t-att-data-validation-float-min="question.validation_min_float_value if question.validation_required else False"
t-att-data-validation-float-max="question.validation_max_float_value if question.validation_required else False"/>
<div class="o_survey_answer_wrapper p-1 rounded">
<input type="number" step="any" class="form-control o_survey_question_numerical_box bg-transparent rounded-0 p-0"
t-att-name="question.id" t-att-placeholder="question.question_placeholder"
t-att-value="answer_lines[0].value_numerical_box if answer_lines else None"
t-att-data-question-type="question.question_type"
t-att-data-validation-float-min="question.validation_min_float_value if question.validation_required else False"
t-att-data-validation-float-max="question.validation_max_float_value if question.validation_required else False"/>
</div>
</template>
<template id="question_scale" name="Question: scale">
<!-- A question already answered that the user resets is marked as skipped and not deleted, -->
<!-- so we use the flag skipped to restore or not the answer state. -->
<t t-set="answer_line" t-value="answer_lines and not answer_lines[0].skipped and answer_lines[0]"/>
<div class="o_survey_answer_wrapper o_survey_form_choice"
t-att-data-name="question.id"
t-att-data-is-skipped-question="is_skipped_question or None"
data-question-type="scale">
<div role="radiogroup" class="btn-group d-flex mb-2" t-att-aria-label="">
<t t-foreach="range(question.scale_min, question.scale_max + 1)" t-as="value">
<t t-set="answer_selected" t-value="answer_line and answer_line.value_scale == value"/>
<label t-attf-class="o_survey_choice_btn flex-shrink-1 rounded text-nowrap #{'me-2' if not value_last else ''} #{'o_survey_selected' if answer_selected else ''}"
t-attf-for="{{ question.id }}_{{ value }}">
<div class="d-none d-md-flex align-items-center fs-5">
<div class="fw-bold my-3 flex-fill align-self-center text-center" t-out="value"/>
<i class="fa fa-check-circle me-1 my-3"/>
<i class="fa fa-circle-thin me-1 my-3"/>
</div>
<div class="d-block d-md-none my-3 text-center fs-5">
<div class="fw-bold" t-out="value"/>
<i class="fa fa-check-circle"/>
<i class="fa fa-circle-thin"/>
</div>
<input autocomplete="off"
class="btn-check"
type="radio"
t-attf-class="o_survey_form_choice_item invisible position-absolute #{'o_survey_form_choice_item_selected' if answer_selected else ''}"
t-att-data-selection-key="letters[value_index] if useKeySelection else ''"
t-attf-name="{{ question.id }}"
t-att-checked="'checked' if answer_selected else None"
t-attf-value="{{ value }}"
t-attf-id="{{ question.id }}_{{ value }}"
/>
</label>
</t>
</div>
<div t-if="question.scale_min_label or question.scale_mid_label or question.scale_max_label"
class="d-flex justify-content-between text-primary">
<div class="text-start" t-out="question.scale_min_label"/>
<div class="text-center" t-out="question.scale_mid_label"/>
<div class="text-end" t-out="question.scale_max_label"/>
</div>
</div>
</template>
<template id="question_date" name="Question: date box">
<div class="input-group o_survey_form_date" t-attf-id="datetimepicker_#{question.id}" data-target-input="nearest"
t-att-data-mindate="question.validation_min_date"
t-att-data-maxdate="question.validation_max_date">
<div class="input-group o_survey_form_date o_survey_answer_wrapper p-1 rounded">
<input type="text" class="form-control datetimepicker-input o_survey_question_date bg-transparent rounded-0 p-0"
t-attf-data-target="#datetimepicker_#{question.id}"
t-att-name="question.id" t-att-placeholder="question.question_placeholder"
t-att-value="format_date(answer_lines[0].value_date) if answer_lines else None"
t-att-data-question-type="question.question_type"/>
<div t-if="not survey_form_readonly" class="position-absolute input-group-text text-primary border-0 bg-transparent p-0" t-attf-data-target="#datetimepicker_#{question.id}" data-toggle="datetimepicker"><i class="fa fa-calendar"></i></div>
t-att-data-question-type="question.question_type"
data-widget="datetime-picker" data-widget-type="date"
t-att-data-min-date="question.validation_min_date"
t-att-data-max-date="question.validation_max_date"/>
<div t-if="not survey_form_readonly" class="position-absolute input-group-text o_input_group_date_icon text-primary border-0 bg-transparent p-0 end-0"><i class="fa fa-calendar"></i></div>
</div>
</template>
<template id="question_datetime" name="Question: datetime box">
<div class="input-group o_survey_form_date" t-attf-id="datetimepicker_#{question.id}" data-target-input="nearest"
t-att-data-mindate="question.validation_min_datetime"
t-att-data-maxdate="question.validation_max_datetime">
<div class="input-group o_survey_form_date o_survey_answer_wrapper p-1 rounded">
<input type="text" class="form-control datetimepicker-input o_survey_question_datetime bg-transparent rounded-0 p-0"
t-attf-data-target="#datetimepicker_#{question.id}"
t-att-name="question.id" t-att-placeholder="question.question_placeholder"
t-att-value="format_datetime(answer_lines[0].value_datetime) if answer_lines else None"
t-att-data-question-type="question.question_type"/>
<div t-if="not survey_form_readonly" class="position-absolute input-group-text text-primary border-0 bg-transparent p-0" t-attf-data-target="#datetimepicker_#{question.id}" data-toggle="datetimepicker"><i class="fa fa-calendar"></i></div>
t-att-data-question-type="question.question_type"
data-widget="datetime-picker" data-widget-type="datetime"
t-att-data-min-date="question.validation_min_datetime"
t-att-data-max-date="question.validation_max_datetime"/>
<div t-if="not survey_form_readonly" class="position-absolute input-group-text o_input_group_date_icon text-primary border-0 bg-transparent p-0 end-0"><i class="fa fa-calendar"></i></div>
</div>
</template>
@ -417,7 +489,7 @@
<!-- Directly use field or route if the user doesn't have access rights -->
<div t-if="not env.user.has_group('survey.group_survey_user')"
class="o_survey_choice_img d-flex my-3 justify-content-center">
<img t-att-src="'/survey/get_question_image/%s/%s/%s/%s' % (survey.access_token, answer.access_token, question.id, label.id)"/>
<img t-att-src="'/survey/get_question_image/%s/%s/%s/%s' % (survey.access_token, answer.access_token, question.id, label.id)" class="mw-100 h-auto"/>
</div>
<div t-else="" t-field="label.value_image"
class="o_survey_choice_img d-flex my-3 justify-content-center"
@ -428,139 +500,133 @@
<template id="question_simple_choice" name="Question: simple choice">
<t t-set="answer_line" t-value="answer_lines.filtered(lambda line: line.suggested_answer_id)"/>
<t t-set="comment_line" t-value="answer_lines.filtered(lambda line: line.value_char_box)"/>
<div class="row o_survey_form_choice"
<div class="row g-2 o_survey_answer_wrapper o_survey_form_choice"
t-att-data-name="question.id"
t-att-data-is-skipped-question="is_skipped_question or None"
data-question-type="simple_choice_radio">
<t t-set="item_idx" t-value="0"/>
<div t-attf-class="col-lg-12 d-flex flex-wrap">
<t t-set="has_correct_answer" t-value="scoring_display_correction and any(label.is_correct for label in question.suggested_answer_ids)"/>
<t t-foreach='question.suggested_answer_ids' t-as='label'>
<t t-set="item_idx" t-value="label_index"/>
<t t-set="answer_selected" t-value="answer_line and answer_line.suggested_answer_id.id == label.id"/>
<t t-set="is_correct" t-value="label.is_correct"/>
<t t-set="has_correct_answer" t-value="scoring_display_correction and any(label.is_correct for label in question.suggested_answer_ids)"/>
<t t-foreach='question.suggested_answer_ids' t-as='label'>
<t t-set="item_idx" t-value="label_index"/>
<t t-set="answer_selected" t-value="answer_line and answer_line.suggested_answer_id.id == label.id"/>
<!--Used for print mode with corrections -->
<t t-set="answer_class" t-if="not has_correct_answer" t-value="''" />
<t t-set="answer_class" t-elif="is_correct" t-value="'bg-success'" />
<t t-set="answer_class" t-elif="not is_correct" t-value="'bg-danger'" />
<!--Used for print mode with corrections -->
<t t-set="answer_class" t-value="'' if not has_correct_answer else 'bg-success' if label.is_correct else 'bg-danger'"/>
<div t-attf-class="col-sm-12 #{use_half_col_lg}">
<label t-att-for="str(question.id) + '_' + str(label.id)"
t-att-class="'o_survey_choice_btn me-2 mb-2 py-1 px-3 rounded %s %s' % (answer_class, 'o_survey_selected' if answer_selected else '')">
t-attf-class="o_survey_choice_btn py-1 px-3 w-100 h-100 rounded #{answer_class} #{'o_survey_selected' if answer_selected else ''}">
<t t-call="survey.survey_selection_key">
<t t-set="selection_key_class" t-value="'position-relative o_survey_radio_btn float-start d-flex'"/>
</t>
<span class="ms-2 text-break" t-field='label.value'/>
<input t-att-id="str(question.id) + '_' + str(label.id)" type="radio" t-att-value='label.id'
t-attf-class="o_survey_form_choice_item invisible position-absolute #{'o_survey_form_choice_item_selected' if answer_selected else ''}"
t-att-name='question.id'
t-att-checked="'checked' if answer_selected else None"
t-att-data-selection-key="letters[item_idx] if useKeySelection else ''"/>
<t t-if="has_correct_answer and answer_selected">
<!-- While displaying results: change icons to have a check mark for a right answer and a cross for a wrong one -->
<i t-if="is_correct" class="float-end mt-1 position-relative d-inline fa fa-check-circle"/>
<i t-if="label.is_correct" class="float-end mt-1 position-relative d-inline fa fa-check-circle"/>
<i t-else="" class="float-end mt-1 position-relative d-inline fa fa-times-circle"/>
</t>
<t t-else="">
<i class="fa fa-check-circle float-end mt-1 position-relative"></i>
<i class="fa fa-circle-thin float-end mt-1 position-relative"></i>
<i class="fa fa-check-circle float-end mt-1 ms-1 position-relative"/>
<i class="fa fa-circle-thin float-end mt-1 ms-1 position-relative"/>
</t>
<input t-att-id="str(question.id) + '_' + str(label.id)" type="radio" t-att-value='label.id'
t-attf-class="o_survey_form_choice_item invisible position-absolute #{'o_survey_form_choice_item_selected' if answer_selected else ''}"
t-att-name='question.id'
t-att-checked="'checked' if answer_selected else None"
t-att-data-selection-key="letters[item_idx] if useKeySelection else ''"/>
<span class="ms-2 text-break" t-field='label.value'/>
<t t-call="survey.question_suggested_value_image"/>
</label>
</t>
</div>
<div t-if='question.comments_allowed and question.comment_count_as_answer' class="js_comments col-lg-12" >
<div class="d-flex flex-wrap">
<label t-att-class="'o_survey_choice_btn form-label me-2 py-1 px-3 rounded %s' % ('o_survey_selected' if comment_line else '')">
</div>
</t>
<t t-if='question.comments_allowed and question.comment_count_as_answer'>
<div t-attf-class="col-sm-12 #{use_half_col_lg}">
<label t-attf-class="o_survey_choice_btn py-1 px-3 h-100 w-100 rounded #{'o_survey_selected' if comment_line else ''}">
<t t-set="item_idx" t-value="item_idx + 1"/>
<t t-call="survey.survey_selection_key">
<t t-set="selection_key_class" t-value="'position-relative o_survey_radio_btn float-start d-flex'"/>
</t>
<i class="fa fa-check-circle float-end mt-1 ms-1 position-relative"/>
<i class="fa fa-circle-thin float-end mt-1 ms-1 position-relative"/>
<input type="radio" class="o_survey_form_choice_item o_survey_js_form_other_comment invisible position-absolute" value="-1"
t-att-name='question.id'
t-att-checked="comment_line and 'checked' or None"
t-att-data-selection-key="letters[item_idx] if useKeySelection else ''"/>
t-att-name='question.id'
t-att-checked="comment_line and 'checked' or None"
t-att-data-selection-key="letters[item_idx] if useKeySelection else ''"/>
<span class="ms-2" t-out="question.comments_message or default_comments_message" />
<i class="fa fa-check-circle float-end mt-1 position-relative"></i>
<i class="fa fa-circle-thin float-end mt-1 position-relative"></i>
</label>
</div>
<div t-attf-class="o_survey_comment_container mt-3 py-0 px-1 #{'d-none' if not comment_line else ''}">
<div t-attf-class="o_survey_comment_container mt-3 py-0 px-1 h-auto #{'d-none' if not comment_line else ''}">
<textarea type="text" class="form-control o_survey_question_text_box bg-transparent rounded-0 p-0"
t-att-disabled="None if comment_line else 'disabled'"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
t-att-disabled="None if comment_line else 'disabled'"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
</div>
</div>
<div t-if='question.comments_allowed and not question.comment_count_as_answer' class="col-lg-12 o_survey_comment_container mx-1 mt-3 ps-3 pe-4">
<textarea type="text" class="form-control o_survey_comment o_survey_question_text_box bg-transparent rounded-0 p-0"
t-att-placeholder="question.comments_message or default_comments_message if not survey_form_readonly else ''"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
</t>
<div t-if='question.comments_allowed and not question.comment_count_as_answer'
class="mb-2 o_survey_comment_container mt-3">
<textarea type="text" class="col form-control o_survey_comment o_survey_question_text_box bg-transparent rounded-0 p-0"
t-att-placeholder="question.comments_message or default_comments_message if not survey_form_readonly else ''"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
</div>
</div>
</template>
<template id="question_multiple_choice" name="Question: multiple choice">
<t t-set="comment_line" t-value="answer_lines.filtered(lambda line: line.value_char_box)"/>
<div class="row o_survey_form_choice o_survey_question_multiple_choice"
<div class="row g-2 o_survey_answer_wrapper o_survey_form_choice o_survey_question_multiple_choice"
t-att-data-name="question.id"
t-att-data-question-type="question.question_type">
<t t-set="item_idx" t-value="0"/>
<div class="d-flex flex-wrap col-lg-12">
<t t-set="has_correct_answer" t-value="scoring_display_correction and any(label.is_correct for label in question.suggested_answer_ids)"/>
<t t-foreach='question.suggested_answer_ids' t-as='label'>
<t t-set="item_idx" t-value="label_index"/>
<t t-set="answer_line" t-value="answer_lines.filtered(lambda line: line.suggested_answer_id == label)"/>
<t t-set="answer_selected" t-value="answer_line and answer_line.suggested_answer_id.id == label.id"/>
<t t-set="is_correct" t-value="label.is_correct"/>
<t t-set="has_correct_answer" t-value="scoring_display_correction and any(label.is_correct for label in question.suggested_answer_ids)"/>
<t t-foreach='question.suggested_answer_ids' t-as='label'>
<t t-set="item_idx" t-value="label_index"/>
<t t-set="answer_line" t-value="answer_lines.filtered(lambda line: line.suggested_answer_id == label)"/>
<t t-set="answer_selected" t-value="answer_line and answer_line.suggested_answer_id.id == label.id"/>
<!--Used for print mode with corrections -->
<t t-set="answer_class" t-if="not has_correct_answer" t-value="''" />
<t t-set="answer_class" t-elif="is_correct" t-value="'bg-success'" />
<t t-set="answer_class" t-elif="not is_correct" t-value="'bg-danger'" />
<!--Used for print mode with corrections -->
<t t-set="answer_class" t-value="'' if not has_correct_answer else 'bg-success' if label.is_correct else 'bg-danger'"/>
<label t-att-class="'o_survey_choice_btn form-label me-2 py-1 px-3 rounded %s %s' % (answer_class, 'o_survey_selected' if answer_line else '')">
<div t-attf-class="col-sm-12 #{use_half_col_lg}">
<label t-attf-class="o_survey_choice_btn py-1 px-3 w-100 h-100 rounded #{answer_class} #{'o_survey_selected' if answer_selected else ''}">
<t t-call="survey.survey_selection_key">
<t t-set="selection_key_class" t-value="'position-relative float-start d-flex'"/>
</t>
<input type="checkbox" t-att-value='label.id' class="o_survey_form_choice_item invisible position-absolute"
t-att-name="question.id"
t-att-checked="'checked' if answer_line else None"
t-att-data-selection-key="letters[item_idx] if useKeySelection else ''"/>
<span class="ms-2 text-break" t-field='label.value'/>
<t t-if="has_correct_answer and answer_selected">
<!-- While displaying results: change icons to have a check mark for a right answer and a cross for a wrong one -->
<i t-if="is_correct" class="float-end mt-1 position-relative d-inline fa fa-check-circle"/>
<i t-else="" class="float-end mt-1 position-relative d-inline fa fa-times-circle"/>
</t>
<!-- While displaying results: change icons to have a check mark for a right answer and a cross for a wrong one -->
<i t-if="has_correct_answer and answer_selected" t-attf-class="float-end mt-1 position-relative d-inline
fa #{'fa-check-square' if is_correct else 'fa-times-square'}"/>
<t t-else="">
<i class="fa fa-check-circle float-end mt-1 position-relative"></i>
<i class="fa fa-circle-thin float-end mt-1 position-relative"></i>
<i class="fa fa-check-square float-end mt-1 ms-1 position-relative"/>
<i class="fa fa-square-o float-end mt-1 ms-1 position-relative"/>
</t>
<input type="checkbox" t-att-value='label.id' class="o_survey_form_choice_item invisible position-absolute"
t-att-name="question.id"
t-att-checked="'checked' if answer_line else None"
t-att-data-selection-key="letters[item_idx] if useKeySelection else ''"/>
<span class="ms-2 text-break" t-field='label.value'/>
<t t-call="survey.question_suggested_value_image"/>
</label>
</t>
</div>
<div t-if='question.comments_allowed and question.comment_count_as_answer' class="js_ck_comments col-lg-12" >
<div class="d-flex flex-wrap">
<label t-att-class="'o_survey_choice_btn form-label me-2 py-1 px-3 rounded %s' % ('o_survey_selected' if comment_line else '')">
</div>
</t>
<t t-if='question.comments_allowed and question.comment_count_as_answer'>
<div t-attf-class="col-sm-12 #{use_half_col_lg}">
<label t-attf-class="o_survey_choice_btn py-1 px-3 h-100 w-100 rounded #{'o_survey_selected' if comment_line else ''}">
<t t-set="item_idx" t-value="item_idx + 1"/>
<t t-call="survey.survey_selection_key">
<t t-set="selection_key_class" t-value="'position-relative float-start d-flex'"/>
</t>
<i class="fa fa-check-square float-end mt-1 ms-1 position-relative"/>
<i class="fa fa-square-o float-end mt-1 ms-1 position-relative"/>
<input type="checkbox" class="o_survey_form_choice_item o_survey_js_form_other_comment invisible position-absolute" value="-1"
t-att-name="question.id"
t-att-checked="comment_line and 'checked' or None"
t-att-data-selection-key="letters[item_idx] if useKeySelection else ''"/>
t-att-name="question.id"
t-att-checked="comment_line and 'checked' or None"
t-att-data-selection-key="letters[item_idx] if useKeySelection else ''"/>
<span class="ms-2" t-out="question.comments_message or default_comments_message" />
<i class="fa fa-check-circle float-end mt-1 position-relative"></i>
<i class="fa fa-circle-thin float-end mt-1 position-relative"></i>
</label>
</div>
<div t-attf-class="o_survey_comment_container mt-3 py-0 px-1 #{'d-none' if not comment_line else ''}">
<div t-attf-class="o_survey_comment_container mt-3 py-0 h-auto px-1 #{'d-none' if not comment_line else ''}">
<textarea type="text" class="form-control o_survey_question_text_box bg-transparent rounded-0 p-0"
t-att-disabled="None if comment_line else 'disabled'"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
t-att-disabled="None if comment_line else 'disabled'"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
</div>
</div>
<div t-if='question.comments_allowed and not question.comment_count_as_answer' class="col-lg-12 o_survey_comment_container mx-1 mt-3 py-0 ps-3 pe-4">
<textarea type="text" class="form-control o_survey_comment o_survey_question_text_box bg-transparent rounded-0 p-0"
t-att-placeholder="question.comments_message or default_comments_message if not survey_form_readonly else ''"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
</t>
<div t-if='question.comments_allowed and not question.comment_count_as_answer' class="mb-2 o_survey_comment_container mt-3">
<textarea type="text" class="col form-control o_survey_comment o_survey_question_text_box bg-transparent rounded-0 p-0"
t-att-placeholder="question.comments_message or default_comments_message if not survey_form_readonly else ''"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
</div>
</div>
</template>
@ -570,7 +636,8 @@
<table class="table table-borderless o_survey_question_matrix text-white text-center mb-0"
t-att-data-name="question.id"
t-att-data-question-type="question.question_type"
t-att-data-sub-questions="question.matrix_row_ids.ids">
t-att-data-sub-questions="question.matrix_row_ids.ids"
t-att-data-is-skipped-question="is_skipped_question or None">
<thead>
<tr>
<th> </th>
@ -624,14 +691,14 @@
<template id="survey_progression" name="Survey: Progression">
<t t-if="len(page_ids) > 1 and not survey.has_conditional_questions">
<t t-set="percentage" t-value="round(100*(page_number/len(page_ids)))"/>
<t t-if="survey.progression_mode == 'percent'">
<span class="o_survey_progress_percent" t-esc="percentage"/> % completed
</t>
<t t-else="">
<span class="o_survey_progress_number" t-esc="page_number"/> of <span t-esc="len(page_ids)"/>
<span t-if="survey.questions_layout == 'page_per_question'">answered</span>
<span t-else="">pages</span>
</t>
<span t-if="survey.progression_mode == 'percent'">
<t t-esc="percentage"/>% completed
</span>
<span t-else="">
<t t-esc="page_number"/> of <t t-esc="len(page_ids)"/>
<t t-if="survey.questions_layout == 'page_per_question'">answered</t>
<t t-else="">pages</t>
</span>
<div class="o_survey_progress progress flex-grow-1">
<div class="progress-bar bg-primary" t-att-style="'width: ' + str(percentage) + '%'"/>
</div>

View file

@ -13,7 +13,7 @@
<h1 class="mt32">403: Forbidden</h1>
<p>The page you were looking for could not be authorized.</p>
<p>Maybe you were looking for
<a t-attf-href="/web#view_type=form&amp;model=survey.survey&amp;id=#{survey.id}&amp;action=survey.action_survey_form">this page</a> ?
<a t-attf-href="/odoo/action-survey.action_survey_form/{{survey.id}}">this page</a> ?
</p>
</div>
</div>
@ -30,7 +30,7 @@
<h1><span t-field="survey.title"/> survey is empty</h1>
<p t-if="env.user.has_group('survey.group_survey_user')">
Please make sure you have at least one question in your survey. You also need at least one section if you chose the "Page per section" layout.<br />
<a t-att-href="'/web#view_type=form&amp;model=survey.survey&amp;id=%s&amp;action=survey.action_survey_form' % survey.id"
<a t-att-href="'/odoo/action-survey.action_survey_form/%s' % survey.id"
class="btn btn-secondary"
groups="survey.group_survey_manager">Edit in backend</a>
</p>
@ -66,7 +66,25 @@
<div class="container">
<div class="jumbotron mt32">
<h1><span t-field="survey.title"/> survey expired</h1>
<p>This survey is now closed. Thank you for your interest !</p>
<p>This survey is now closed. Thank you for your interest!</p>
</div>
</div>
</div>
</t>
</template>
<!-- Access error survey page -->
<template id="survey_access_error" name="Survey: access error">
<t t-call="survey.layout">
<div class="wrap">
<div class="container">
<div class="jumbotron mt32">
<h1>Survey Access Error</h1>
<p>Oopsie! We could not let you open this survey. Make sure you are using the correct link and are allowed to
participate or get in touch with its organizer.</p>
<a class="btn btn-secondary" href="/">
Leave
</a>
</div>
</div>
</div>
@ -78,29 +96,35 @@
<!-- ============================================================ -->
<template id="survey_button_form_view" name="Survey: back to form view">
<div groups="survey.group_survey_manager" t-ignore="true" class="alert alert-info p-2 border-0 rounded-0 d-print-none css_editable_mode_hidden mb-0">
<div t-ignore="true" class="text-center">
<a t-attf-href="/web#view_type=form&amp;model=survey.survey&amp;id=#{survey.id}&amp;action=survey.action_survey_form"><span t-if="answer and answer.test_entry">This is a Test Survey. </span><i class="fa fa-fw fa-arrow-right"/>Edit Survey</a>
<div t-ignore="true" t-if="answer and answer.test_entry" class="alert alert-info p-2 border-0 rounded-0 d-print-none css_editable_mode_hidden mb-0 text-center">
<p class="mb-1">This is a Test Survey Entry.</p>
<div class="survey_button_form_view_hook d-inline-block">
<a t-if="env.user.has_group('survey.group_survey_user')" t-attf-href="/odoo/action-survey.action_survey_form/{{survey.id}}">
<i class="oi oi-fw oi-arrow-right"/>Go to Survey</a>
</div>
</div>
<div groups="survey.group_survey_user" t-if="survey.scoring_type != 'no_scoring' and survey.scoring_max_obtainable &lt;= 0"
t-ignore="true" class="alert alert-warning p-2 border-0 rounded-0 d-print-none css_editable_mode_hidden mb-0 text-center">
<i class="fa fa-exclamation-triangle"/> It is currently not possible to pass this assessment because no question is configured to give any points.
</div>
</template>
<template id="survey_button_retake" name="Survey: retake button">
<div>
<t t-if="not answer.scoring_success and not answer.is_session_answer">
<t t-if="survey.is_attempts_limited">
<t t-set="attempts_left" t-value="survey._get_number_of_attempts_lefts(answer.partner_id, answer.email, answer.invite_token)" />
<t t-if="attempts_left > 0">
<p><span>Number of attempts left</span>: <span t-esc="attempts_left"></span></p>
<p><a role="button" class="btn btn-primary btn-lg" t-att-href="'/survey/retry/%s/%s' % (survey.access_token, answer.access_token)">
Retry</a></p>
</t>
</t>
<t t-else="">
<p><a role="button" class="btn btn-primary btn-lg" t-att-href="'/survey/retry/%s/%s' % (survey.access_token, answer.access_token)">
Take Again</a></p>
</t>
<div t-if="not answer.is_session_answer and not (survey.certification and answer.scoring_success)" class="d-print-none">
<t t-if="survey.is_attempts_limited">
<t t-set="attempts_left" t-value="survey._get_number_of_attempts_lefts(answer.partner_id, answer.email, answer.invite_token)" />
<p t-if="attempts_left > 0">
<span>Number of attempts left</span>: <span t-out="attempts_left"/>
<a role="button" class="btn btn-primary btn-lg ms-3" t-att-href="'/survey/retry/%s/%s' % (survey.access_token, answer.access_token)">
Retry
</a>
</p>
</t>
<p t-else="">
<a role="button" class="btn btn-primary btn-lg" t-att-href="'/survey/retry/%s/%s' % (survey.access_token, answer.access_token)">
Take Again
</a>
</p>
</div>
</template>
@ -144,15 +168,16 @@
<button
t-if="survey and survey.users_can_go_back"
t-att-disabled="not can_go_back"
type="submit" class="btn border-start p-0 shadow-none o_survey_navigation_submit" name="button_submit" value="previous" t-att-data-previous-page-id="previous_page_id">
<i class="fa fa-chevron-left p-2" />
type="submit" class="btn border-0 p-0 shadow-none o_survey_navigation_submit" name="button_submit" value="previous" t-att-data-previous-page-id="previous_page_id">
<i class="oi oi-chevron-left p-2" />
</button>
<t t-set="can_go_forward"
t-value="survey and survey.questions_layout in ['page_per_question', 'page_per_section'] and answer and answer.state != 'done' and not answer.is_session_answer"/>
<button
t-att-disabled="not can_go_forward"
type="submit" class="btn border-start p-0 shadow-none o_survey_navigation_submit" t-att-value="'next' if not survey_last else 'finish'">
<i class="fa fa-chevron-right p-2" />
type="submit" class="btn border-0 p-0 shadow-none o_survey_navigation_submit" t-att-value="'next' if not survey_last else 'finish'">
<t t-if="survey_last">Submit</t>
<i class="oi oi-chevron-right p-2" />
</button>
</div>
</template>

View file

@ -7,29 +7,46 @@
<t t-set="survey_form_readonly" t-value="true"/>
<t t-if="answer.test_entry" t-call="survey.survey_button_form_view" />
<div class="wrap">
<div class="o_survey_print container">
<div class='py-5 mt32'>
<div class="o_survey_print o_container_small">
<div class="pt-5 mt32">
<h1><span t-field='survey.title' class="text-break"/></h1>
<t t-if="survey.description"><div t-field='survey.description' class="oe_no_empty text-break"/></t>
<t t-if="review" t-call="survey.survey_button_retake"/>
<div class="d-flex gap-2">
<t t-if="review" t-call="survey.survey_button_retake"/>
<p><a role="button" title="Print Results" class="btn btn-secondary btn-lg d-print-none o_survey_user_results_print">
<i class="fa fa-print"/>
</a></p>
</div>
</div>
<div role="form">
<div t-if="graph_data" class="o_survey_result px-4">
<div class="survey_graph mb-4"
data-graph-type="doughnut"
t-att-data-graph-data="graph_data">
<canvas id="doughnut_chart" class="w-100 h-auto mx-auto"></canvas>
</div>
<div t-if="survey.page_ids" class="survey_graph d-none d-md-block"
data-graph-type="by_section"
t-att-data-graph-data="graph_data">
<canvas id="by_section_chart" class="w-100 h-auto mx-auto"></canvas>
</div>
</div>
<div class="mt-5">
<fieldset disabled="disabled">
<t t-set="question" t-value="False" />
<t t-foreach='survey.question_and_page_ids' t-as='question'>
<t t-if="question.is_page and
(any(q in questions_to_display for q in question.question_ids)
or not is_html_empty(question.description))">
<hr t-if="question != survey.page_ids[0]" />
<hr t-if="question != survey.page_ids[0]" class="my-5"/>
<div class="o_page_header mb-5">
<h1 t-field='question.title' class="text-break" />
<h1 t-field='question.title' class="text-break fs-2" />
<div t-if="question.description" t-field='question.description' class="oe_no_empty"/>
</div>
</t>
<t t-if="not question.is_page and not answer or (question in answer.predefined_question_ids &amp; questions_to_display)" >
<t t-set="answer_lines" t-value="answer.user_input_line_ids.filtered(lambda line: line.question_id == question)"/>
<div class="js_question-wrapper" t-att-id="question.id">
<h2>
<h2 class="fs-4">
<span t-field='question.title' class="text-break"/>
<span t-if="question.constr_mandatory" class="text-danger">*</span>
<span t-if="scoring_display_correction" class="badge rounded-pill" t-att-data-score-question="question.id"></span>
@ -58,7 +75,9 @@
</t>
<t t-else="">
<t t-if="question.question_type == 'text_box'" t-call="survey.question_text_box"/>
<t t-if="question.question_type == 'char_box'" t-call="survey.question_char_box"/>
<t t-if="question.question_type == 'char_box'" class="o_survey_print o_survey_comment_container p-0">
<span t-out="answer_lines[0].value_char_box or None"/>
</t>
<t t-if="question.question_type == 'numerical_box'" t-call="survey.question_numerical_box"/>
<t t-if="question.question_type == 'date'" t-call="survey.question_date"/>
<t t-if="question.question_type == 'datetime'" t-call="survey.question_datetime"/>
@ -87,9 +106,10 @@
</t>
</t>
<t t-if="question.question_type == 'simple_choice'" t-call="survey.question_simple_choice"/>
<t t-if="question.question_type == 'scale'" t-call="survey.question_scale"/>
<t t-if="question.question_type == 'multiple_choice'" t-call="survey.question_multiple_choice"/>
<t t-if="question.question_type == 'matrix'" t-call="survey.question_matrix"/>
<t t-if="question.question_type in ['simple_choice', 'multiple_choice','matrix']">
<t t-if="question.question_type in ['simple_choice', 'multiple_choice', 'matrix', 'scale']">
<t t-if="answer_lines">
<t t-if="answer_lines[0].skipped">
<div class="row g-0">

View file

@ -2,10 +2,12 @@
<odoo>
<data>
<template id="survey_page_statistics" name="Survey: result statistics page">
<t t-set="no_livechat" t-value="True"/>
<t t-set="no_survey_navigation" t-value="True"/>
<t t-call="survey.layout">
<t t-call="survey.survey_button_form_view" />
<t t-set="page_record_limit" t-value="10"/><!-- Change this record_limit to change number of record per page-->
<div class="container o_survey_result">
<div class="o_container_small o_survey_result">
<t t-call="survey.survey_page_statistics_header" />
<t t-call="survey.survey_page_statistics_inner" />
</div>
@ -13,48 +15,66 @@
</template>
<template id="survey_page_statistics_header" name="Survey: result statistics header">
<div class="o_survey_statistics_header pt-5 mt32">
<h1>
<span t-field="survey.title"/>
<span style="font-size:1.5em;"
t-attf-class="fa fa-bar-chart-o #{'fa-bar-chart-o' if survey.scoring_type == 'no_scoring' else 'fa-trophy' if survey.certification else 'fa-question-circle-o'} float-end " role="img" aria-label="Chart" title="Chart"/>
</h1>
<div t-field="survey.description" class="oe_no_empty"/>
<h2 t-if="not question_and_page_data">
Sorry, no one answered this survey yet.
</h2>
<div class="o_survey_statistics_header mt32">
<h2 t-field="survey.title"/>
<div class="d-flex align-items-start">
<div t-if="question_and_page_data" class="o_survey_results_topbar d-print-none"><t t-call="survey.survey_results_filters"/></div>
<h3 t-else="">
Sorry, no one answered this survey yet.
</h3>
<button class="btn btn-primary d-print-none o_survey_results_print mt-1 ms-auto" aria-label="Print" title="Print">
<i class="fa fa-print"/>
</button>
</div>
</div>
</template>
<template id="survey_page_statistics_inner" name="Survey: result statistics content">
<div t-if="survey.session_show_leaderboard" class="o_survey_session_leaderboard mb-5 mt-1">
<t t-set="already_filtered_questions" t-value="{filter['question_id'] for filter in search_filters}"/>
<div t-if="survey.session_show_leaderboard and leaderboard" class="o_survey_session_leaderboard mb-5 mt-1">
<h2 class="mt16 text-uppercase text-muted">Leaderboard</h2>
<t t-call="survey.user_input_session_leaderboard"/>
</div>
<div t-if="question_and_page_data" class="o_survey_results_topbar rounded d-print-none mb-5">
<t t-call="survey.survey_results_filters"/>
</div>
<div t-if="survey.scoring_type in ['scoring_with_answers', 'scoring_without_answers']">
<h2 class="mt16 text-uppercase text-muted">Results Overview</h2>
<div>Success rate: <span class="fw-bold"><t t-call="survey.survey_remove_unnecessary_decimals">
<t t-set="value_to_format" t-value="survey_data['global_success_rate']"/></t>%</span></div>
<div class="survey_graph" data-graph-type="pie" t-att-data-graph-data="survey_data['global_success_graph']">
<!-- canvas element for drawing pie chart -->
<canvas/>
</div>
<hr class="my-2"/>
<div class="row mt-2">
<div class="col">
<h4 class="text-primary" t-out="survey.question_count"/>
<h6>Questions</h6>
</div>
<div class="col">
<h4 class="text-primary" t-out="survey.answer_count"/>
<h6>Registered</h6>
</div>
<div class="col">
<h4 class="text-primary" t-out="survey.answer_done_count"/>
<h6>Completed</h6>
</div>
<div class="d-sm-none w-100"/>
<div class="col">
<h4 class="text-primary"><t t-call="survey.survey_remove_unnecessary_decimals">
<t t-set="value_to_format" t-value="survey_data['global_success_rate']"/></t>%</h4>
<h6>Success rate</h6>
</div>
<div t-if="survey.answer_duration_avg" class="col">
<h4 class="text-primary" t-out="survey.answer_duration_avg" t-options="{'widget': 'float_time'}"/>
<h6>Average Duration</h6>
</div>
<div t-if="survey.answer_score_avg" class="col">
<h4 class="text-primary"><t t-out="round(survey.answer_score_avg, 2)"/>%</h4>
<h6>Average Score</h6>
</div>
</div>
<hr/>
</div>
<div t-foreach="question_and_page_data" t-as='question_data'>
<t t-set="question" t-value="question_data['question']"/>
<t t-if="question_data['is_page']">
<h2 class="mt16 text-uppercase text-muted" t-field="question.title"/>
<div t-field="question.description" class="oe_no_empty" />
<hr class="mt-2 mb-2"/>
</t>
<div t-else="" class="ms-4 mt-5">
<t t-call="survey.survey_page_statistics_question" />
<div t-if="question_data['is_page']" class="o_survey_question_page">
<h3 class="mt16 text-uppercase" t-field="question.title"/>
<hr class="mt-2 mb-4"/>
</div>
<div t-else="" class="mt-2 o_survey_results_question_wrapper"><t t-call="survey.survey_page_statistics_question"/></div>
</div>
</template>
@ -62,70 +82,106 @@
<t t-set="comment_lines" t-value="question_data['comment_line_ids']"/>
<t t-set="graph_data" t-value="question_data['graph_data']"/>
<t t-set="table_data" t-value="question_data['table_data']"/>
<t t-set="question_has_image_answers" t-value="any(answer.value_image_filename for answer in question.suggested_answer_ids)"/>
<div class="o_survey_results_question pb-5 border-bottom">
<div class="row mb-3">
<div class="col-sm-6">
<h5 t-field="question.title" class="me-3"/>
</div>
<!-- Question info -->
<div class="col-sm-6 text-sm-end">
<span class="badge text-bg-info ms-0 ms-sm-1 me-1 me-sm-0" t-field='question.question_type'/>
<t t-if="question.question_type == 'matrix'">
<span class="badge text-bg-info ms-0 ms-sm-1 me-1 me-sm-0" t-field='question.matrix_subtype'/>
</t>
<!-- Scoring info -->
<t t-if="question.question_type in ['numerical_box', 'date', 'datetime']">
<span class="badge text-bg-success ms-0 ms-sm-1 me-1 me-sm-0"><span t-esc="question_data['right_inputs_count']" class="me-1"/>Correct</span>
<t t-if="question.question_type in ['simple_choice', 'multiple_choice']">
<span class="badge text-bg-warning ms-0 ms-sm-1 me-1 me-sm-0" t-if="question.question_type == 'multiple_choice'">
<span t-esc="question_data['partial_inputs_count']" class="me-1"/>Partial
<div class="o_survey_results_question pb-3">
<t t-set="question_answered" t-value="question_data['answer_input_done_ids']"/>
<div class="o_survey_results_question_header">
<div class="d-inline-flex flex-nowrap align-items-center cursor-pointer user-select-none" aria-expanded="true"
data-bs-toggle="collapse" t-attf-data-bs-target=".o_survey_results_question_#{question.id}">
<i class="fa fa-caret-right d-print-none me-3" role="img"/>
<i class="fa fa-caret-down d-print-none me-3" role="img"/>
<h5 t-field="question.title" class="mb-1"/>
</div>
<div t-attf-class="d-flex flex-wrap align-items-center mb-1 collapse show o_survey_results_question_#{question.id}">
<!-- Question info -->
<div class="d-flex align-items-center my-1 me-2">
<!-- Scoring info -->
<t t-if="survey.scoring_type != 'no_scoring' and (question.answer_numerical_box or question.answer_date or
question.answer_datetime or any([a.is_correct for a in question.suggested_answer_ids]))">
<span t-if="question.question_type in ['numerical_box', 'date', 'datetime', 'simple_choice', 'multiple_choice']"
class="badge d-flex gap-1 ms-0 me-1 text-info text-start border rounded">
<span t-out="question_data['right_inputs_count']"/>
<span class="text-success">Correct</span>
</span>
<span t-if="question.question_type == 'multiple_choice'" class="badge d-flex gap-1 ms-0 me-1 text-info text-start border rounded">
<span t-esc="question_data['partial_inputs_count']"/>
<span class="text-warning">Partial</span>
</span>
</t>
<!-- Inputs info -->
<span class="badge d-flex gap-1 ms-0 me-1 text-info text-start border rounded">
<span t-out="len(question_data['answer_input_done_ids'])"/>/
<span t-out="len(question_data['answer_input_ids'])"/>
<span class="text-muted">Responded</span>
</span>
</t>
</t>
<!-- Inputs info -->
<span class="badge text-bg-info ms-0 ms-sm-1 me-1 me-sm-0">
<span t-esc="len(question_data['answer_input_done_ids'])" class="me-1"/>Responded
</span>
<span class="badge text-bg-info ms-0 ms-sm-1 me-1 me-sm-0">
<span t-esc="len(question_data['answer_input_skipped_ids'])" class="me-1"/>Skipped
</span>
</div>
<!-- Numerical KPIs -->
<span t-if="question.question_type in ['numerical_box', 'scale']" class="d-flex gap-1 my-1 me-2">
<div class="btn-group o_survey_results_question_pill" role="group" aria-label="Maximum">
<span class="badge text-bg-secondary only_left_radius px-2 pt-1">Max</span>
<span class="badge text-bg-success only_right_radius px-2 pt-1" t-esc="question_data['numerical_max']"></span>
</div>
<div class="btn-group o_survey_results_question_pill" role="group" aria-label="Minimum">
<span class="badge text-bg-secondary only_left_radius px-2 pt-1">Min</span>
<span class="badge text-bg-danger only_right_radius px-2 pt-1" t-esc="question_data['numerical_min']"></span>
</div>
<div class="btn-group o_survey_results_question_pill" role="group" aria-label="Average">
<span class="badge text-bg-secondary only_left_radius px-2 pt-1">Avg</span>
<span class="badge text-bg-warning only_right_radius px-2 pt-1" t-esc="question_data['numerical_average']"></span>
</div>
</span>
<!-- Data buttons -->
<ul t-if="question.question_type not in ['text_box', 'char_box'] and question_answered"
class="nav btn-group flex-nowrap d-print-none ms-auto" role="tablist">
<li t-if="question.question_type in ['simple_choice', 'multiple_choice', 'matrix', 'scale']" class="nav-item btn-group">
<a t-att-href="'#survey_graph_question_%d' % question.id" t-att-aria-controls="'survey_graph_question_%d' % question.id"
data-bs-toggle="tab" role="tab" class="o_survey_results_data_tab nav-link btn btn-light py-1 px-2 active">
<i t-if="question.question_type == 'simple_choice'" class="fa fa-pie-chart"/>
<i t-else="" class="fa fa-bar-chart-o"/>
</a>
</li>
<li t-elif="question.question_type in ['numerical_box', 'date', 'datetime']" class="nav-item btn-group">
<a t-att-href="'#survey_stats_question_%d' % question.id" t-att-aria-controls="'survey_stats_question_%d' % question.id"
data-bs-toggle="tab" role="tab" class="o_survey_results_data_tab nav-link btn btn-light py-1 px-2 active">
<i class="fa fa-trophy"/>
</a>
</li>
<li class="nav-item btn-group">
<a t-att-href="'#survey_data_question_%d' % question.id" t-att-aria-controls="'survey_data_question_%d' % question.id"
data-bs-toggle="tab" role="tab" class="o_survey_results_data_tab nav-link btn btn-light py-1 px-2">
<i class="fa fa-bars"/>
</a>
</li>
</ul>
</div>
</div>
<div t-attf-class="collapse show o_survey_results_question_#{question.id}">
<!-- Question Description -->
<div class="o_survey_question_description ms-3 text-muted d-none" t-field="question.description"/>
<!-- Answers -->
<div t-if="not question_answered" class="o_survey_no_answers text-center fw-bold">
<p>No answers yet!</p>
</div>
<t t-elif="question.question_type in ['text_box', 'char_box']"
t-call="survey.question_result_text"/>
<t t-elif="question.question_type in ['numerical_box', 'date', 'datetime']"
t-call="survey.question_result_number_or_date_or_datetime"/>
<t t-elif="question.question_type in ['simple_choice', 'multiple_choice', 'scale']"
t-call="survey.question_result_choice"/>
<t t-elif="question.question_type in ['matrix']"
t-call="survey.question_result_matrix"/>
</div>
</div>
<!-- Question Description -->
<div class="ms-3 text-muted" t-field="question.description"/>
<!-- Answers -->
<t t-set="question_answered" t-value="question_data['answer_input_done_ids']"/>
<div t-if="not question_answered" class="alert alert-secondary m-3" role="alert">
No one answered this question.
</div>
<t t-if="question_answered and question.question_type in ['text_box', 'char_box']"
t-call="survey.question_result_text"/>
<t t-elif="question_answered and question.question_type in ['numerical_box', 'date', 'datetime']"
t-call="survey.question_result_number_or_date_or_datetime"/>
<t t-elif="question.question_type in ['simple_choice', 'multiple_choice']"
t-call="survey.question_result_choice"/>
<t t-elif="question.question_type in ['matrix']"
t-call="survey.question_result_matrix"/>
</div>
</template>
<template id="survey_results_filters" name="Survey: Filter results">
<t t-set="search_passed_or_failed" t-value="search_failed or search_passed"/>
<div class="card-header">
<span class="fa fa-filter me-1"/>Filters
<span t-if="search_filters or search_finished or search_passed_or_failed"
class="o_survey_results_topbar_clear_filters text-primary ms-4">
<i class="fa fa-trash me-1"/>Remove all filters
</span>
</div>
<div class="question_and_page_data o_survey_result p-0">
<nav class="navbar navbar-light rounded">
<nav class="navbar navbar-light rounded p-0">
<div t-if="question_and_page_data" class="justify-content-between w-100">
<ul class="nav o_survey_results_topbar_dropdown_filters">
<ul class="nav o_survey_results_topbar_dropdown_filters align-items-center">
<t t-set="dropdown_item_classes" t-translation="off">dropdown-item d-flex align-items-center justify-content-between</t>
<li class="nav-item dropdown me-2 my-1">
<a href="#" role="button" data-bs-toggle="dropdown"
@ -166,23 +222,24 @@
</a>
</div>
</li>
<li t-if="search_filters or search_finished or search_passed_or_failed" class="my-2">
<span class="o_survey_results_topbar_clear_filters text-primary">
<i class="fa fa-trash me-1"/>Remove all filters
</span>
</li>
</ul>
<ul class="nav o_survey_results_topbar_answer_filters mt-2">
<ul class="nav o_survey_results_topbar_answer_filters">
<t t-if="search_filters">
<li t-foreach="search_filters" t-as="filter_data" class="nav-item me-2 my-1">
<span t-attf-class="btn btn-light filter-remove-answer cursor-default">
<span t-esc="filter_data['question']"/> | <span t-esc="filter_data['answers']"></span>
<span t-esc="filter_data['question']"/> | <span t-esc="filter_data['answer']"></span>
<i class="fa fa-times filter-remove-answer text-primary"
t-att-data-row-id="filter_data['row_id']" t-att-data-answer-id="filter_data['answer_id']"></i>
t-att-data-model-short-key="filter_data['model_short_key']"
t-att-data-row-id="filter_data['row_id']"
t-att-data-record-id="filter_data['record_id']"></i>
</span>
</li>
</t>
<t t-else="">
<p class="my-auto text-muted fst-italic">
<span>Click on the filter icon (<span class="fa fa-filter text-primary"/>)
next to an answer to filter surveys on similar answers only.</span>
</p>
</t>
</ul>
</div>
</nav>
@ -190,81 +247,33 @@
</template>
<template id="question_result_text" name="Question: text result (text_box, char_box)">
<table class="table table-hover table-sm" t-att-id="'survey_table_question_%d' % question.id">
<thead>
<tr>
<th>#</th>
<th>User Responses</th>
</tr>
</thead>
<tbody>
<t t-foreach="table_data" t-as="input_line">
<tr t-if="not input_line.skipped" t-att-class="'d-none' if input_line_index >= page_record_limit else ''">
<td>
<t t-if="no_print_url"><t t-esc="input_line_index + 1"></t></t>
<t t-else="">
<a t-att-href="input_line.user_input_id.get_print_url()">
<t t-esc="input_line_index + 1"></t>
</a>
</t>
</td>
<td>
<t t-if="question.question_type == 'text_box'">
<span t-if="no_print_url" t-field="input_line.value_text_box" />
<a t-else="" t-att-href="input_line.user_input_id.get_print_url()" t-field="input_line.value_text_box"></a>
</t>
<t t-if="question.question_type == 'char_box'">
<span t-if="no_print_url" t-field="input_line.value_char_box" />
<a t-else="" t-att-href="input_line.user_input_id.get_print_url()" t-field="input_line.value_char_box"></a>
</t>
</td>
</tr>
</t>
</tbody>
</table>
<t t-call="survey.question_table_pagination"/>
<t t-set="answers_json" t-value="question_data['answers_data']"/>
<t t-set="hide_filter" t-value="question.id in already_filtered_questions or len(table_data) == 1"/>
<div class="survey_table_with_pagination" t-att-data-answers-json="answers_json" t-att-data-hide-filter="hide_filter" t-att-data-record_limit="page_record_limit">
<div class="o_survey_results_table_wrapper overflow-auto">
<table class="table table-hover table-sm o_survey_results_table_indexed" t-att-id="'survey_table_question_%d' % question.id">
<thead>
<tr>
<th>#</th>
<th>User Responses</th>
</tr>
</thead>
<!-- The following tbody tag is populated by the interaction survey_result_pagination
(see also the template survey.paginated_results_rows) -->
<tbody/>
</table>
</div>
<t t-call="survey.question_table_pagination"/>
</div>
</template>
<template id="question_result_number_or_date_or_datetime" name="Question: number or date (and time) result (numerical_box or date or datetime)">
<t t-if="question.question_type == 'numerical_box'">
<span class="float-end mt8">
<div class="btn-group o_survey_results_question_pill" role="group" aria-label="Maximum">
<span class="badge text-bg-secondary only_left_radius px-2 pt-1">Maximum </span>
<span class="badge text-bg-success only_right_radius px-2 pt-1" t-esc="question_data['numerical_max']"></span>
</div>
<div class="btn-group o_survey_results_question_pill" role="group" aria-label="Minimum">
<span class="badge text-bg-secondary only_left_radius px-2 pt-1">Minimum </span>
<span class="badge text-bg-danger only_right_radius px-2 pt-1" t-esc="question_data['numerical_min']"></span>
</div>
<div class="btn-group o_survey_results_question_pill" role="group" aria-label="Average">
<span class="badge text-bg-secondary only_left_radius px-2 pt-1">Average </span>
<span class="badge text-bg-warning only_right_radius px-2 pt-1" t-esc="question_data['numerical_average']"></span>
</div>
</span>
</t>
<ul class="nav nav-tabs d-print-none" role="tablist">
<li class="nav-item">
<a t-att-href="'#survey_stats_question_%d' % question.id"
t-att-aria-controls="'survey_stats_question_%d' % question.id"
class="nav-link active" data-bs-toggle="tab" role="tab">
<i class="fa fa-list-ol me-1"/>Most Common
</a>
</li>
<li class="nav-item">
<a t-att-href="'#survey_data_question_%d' % question.id"
t-att-aria-controls="'survey_data_question_%d' % question.id"
class="nav-link" data-bs-toggle="tab" role="tab">
<i class="fa fa-list-alt me-1"/>All Data
</a>
</li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active with-3d-shadow with-transitions" t-att-id="'survey_stats_question_%d' % question.id">
<table class="table table-hover table-sm">
<thead>
<tr>
<th>User Responses</th>
<th>Top User Responses</th>
<th>Occurrence</th>
<th t-if="question.is_scored_question">Score</th>
</tr>
@ -274,7 +283,7 @@
<td>
<t t-if="question.question_type == 'numerical_box'">
<t t-set="right_answer" t-value="common_line[0] == question.answer_numerical_box"/>
<span t-call="survey.survey_remove_unnecessary_decimals"><t t-set="value_to_format" t-value="common_line[0]"/></span>
<span><t t-call="survey.survey_remove_unnecessary_decimals" value_to_format="common_line[0]"/></span>
<i t-if="right_answer" class="fa fa-check"/>
</t>
<t t-elif="question.question_type == 'date'">
@ -290,8 +299,8 @@
</td>
<td><span t-esc="common_line[1]"></span></td>
<td t-if="question.is_scored_question">
<span t-if="right_answer" t-call="survey.survey_remove_unnecessary_decimals">
<t t-set="value_to_format" t-value="question.answer_score"/>
<span t-if="right_answer">
<t t-call="survey.survey_remove_unnecessary_decimals" value_to_format="question.answer_score"/>
</span>
<span t-else="">0</span>
</td>
@ -300,77 +309,46 @@
</table>
</div>
<div role="tabpanel" class="tab-pane" t-att-id="'survey_data_question_%d' % question.id">
<table class="table table-hover table-sm" t-att-id="'survey_table_question_%d' % question.id">
<thead>
<tr>
<th>#</th>
<th>User Responses</th>
</tr>
</thead>
<tbody>
<t t-foreach="table_data" t-as="input_line">
<tr t-if="not input_line.skipped" t-att-class="'d-none' if input_line_index >= page_record_limit else ''">
<td>
<t t-if="no_print_url"><t t-esc="input_line_index + 1"></t></t>
<t t-else="">
<a t-att-href="input_line.user_input_id.get_print_url()">
<t t-esc="input_line_index + 1"></t>
</a>
</t>
</td>
<td>
<a t-if="question.question_type == 'numerical_box'" t-att-href="input_line.user_input_id.get_print_url()" t-field="input_line.value_numerical_box"/>
<a t-if="question.question_type == 'date'" t-att-href="input_line.user_input_id.get_print_url()" t-field="input_line.value_date"/>
<t t-if="question.question_type == 'datetime'">
<span t-if="no_print_url" t-field="input_line.value_datetime"/>
<a t-else="" t-att-href="input_line.user_input_id.get_print_url()" t-field="input_line.value_datetime"></a>
</t>
</td>
</tr>
</t>
</tbody>
</table>
<t t-call="survey.question_table_pagination"/>
<t t-set="answers_json" t-value="question_data['answers_data']"/>
<t t-set="hide_filter" t-value="question.id in already_filtered_questions or len(table_data) == 1"/>
<div class="survey_table_with_pagination" t-att-data-answers-json="answers_json" t-att-data-hide-filter="hide_filter" t-att-data-record_limit="page_record_limit">
<div class="o_survey_results_table_wrapper overflow-auto">
<table class="table table-hover table-sm o_survey_results_table_indexed" t-att-id="'survey_table_question_%d' % question.id">
<thead>
<tr>
<th>#</th>
<th>User Responses</th>
</tr>
</thead>
<!-- The following tbody tag is populated by the interaction survey_result_pagination
(see also the template survey.paginated_results_rows) -->
<tbody/>
</table>
</div>
<t t-call="survey.question_table_pagination"/>
</div>
</div>
</div>
</template>
<template id="question_result_choice" name="Question: choice result (simple_choice, multiple_choice)">
<ul class="nav nav-tabs d-print-none" role="tablist">
<li t-if="question_answered" class="nav-item">
<a t-att-href="'#survey_graph_question_%d' % question.id"
t-att-aria-controls="'survey_graph_question_%d' % question.id"
class="nav-link active" data-bs-toggle="tab" role="tab">
<i class="fa fa-bar-chart-o"></i>
<span t-if="question.question_type == 'simple_choice'">Pie Graph</span>
<span t-else="">Graph</span>
</a>
</li>
<li class="nav-item">
<a t-att-href="'#survey_data_question_%d' % question.id"
t-att-aria-controls="'survey_data_question_%d' % question.id"
t-attf-class="nav-link #{'active' if not question_answered else ''}"
data-bs-toggle="tab" role="tab">
<i class="fa fa-list-alt me-1"/>Data
</a>
</li>
</ul>
<template id="question_result_choice" name="Question: choice result (simple_choice, multiple_choice, scale)">
<div class="tab-content">
<div t-if="question_answered" role="tabpanel" class="tab-pane active survey_graph"
t-att-id="'survey_graph_question_%d' % question.id"
t-att-data-question-id="question.id"
t-att-data-graph-type="'pie' if question.question_type == 'simple_choice' else 'bar'"
t-att-data-graph-data="graph_data"
t-att-data-right-answers="list(question_data['right_answers'].mapped('value'))">
t-att-data-right-answers="list(question_data['answer_line_done_ids'].mapped('value_scale')) if question.question_type in ['scale'] else list(question_data['right_answers'].mapped('value'))">
<!-- canvas element for drawing bar chart -->
<canvas/>
<canvas class="mx-auto w-100 h-auto"/>
</div>
<div role="tabpanel" t-att-id="'survey_data_question_%d' % question.id"
t-attf-class="tab-pane #{'active' if not question_answered else ''}">
<table class="table table-hover">
t-attf-class="tab-pane #{'active' if not question_answered else ''} table-responsive">
<table class="table table-hover table-sm">
<thead>
<tr>
<th>Answer</th>
<th t-if="question_has_image_answers">Image</th>
<th>User Choice</th>
<th t-if="question.is_scored_question">Score</th>
</tr>
@ -378,53 +356,41 @@
<tbody>
<tr t-foreach="table_data" t-as="choice_data">
<td>
<p>
<span t-if="question.question_type == 'numerical_box'" t-call="survey.survey_remove_unnecessary_decimals">
<t t-set="value_to_format" t-value="choice_data['value']"/>
<p class="text-nowrap my-0">
<span t-if="question.question_type == 'numerical_box'">
<t t-call="survey.survey_remove_unnecessary_decimals" value_to_format="choice_data['value']"/>
</span>
<span t-else="" t-esc="choice_data['value']"/>
<i t-if="question.is_scored_question and choice_data['suggested_answer'].is_correct" class="fa fa-check"/>
</p>
</td>
<td class="o_survey_answer">
<td t-if="question_has_image_answers">
<div t-if="choice_data['suggested_answer'].value_image"
t-field="choice_data['suggested_answer'].value_image"
t-options='{"widget": "image", "qweb_img_responsive": False, "class": "o_image_64_max o_survey_answer_image", "alt-field": "name", "itemprop": "image"}'/>
</td>
<td class="o_survey_answer d-flex align-items-center gap-1">
<span t-esc="round(choice_data['count'] * 100.0/ (len(question_data['answer_line_done_ids']) or 1), 2)"></span> %
<span t-out="choice_data['count_text']" class="badge text-bg-primary"/>
<i t-if="choice_data['suggested_answer'].id and choice_data['count']"
class="fa fa-filter text-primary filter-add-answer"
t-att-data-question-id="question.id"
t-att-data-answer-id="choice_data['suggested_answer'].id"
class="fa fa-filter text-primary filter-add-answer d-print-none"
data-model-short-key="A" t-att-data-record-id="choice_data['suggested_answer'].id"
role="img" aria-label="Filter surveys" title="Only show survey results having selected this answer"/>
</td>
<td t-if="question.is_scored_question" t-call="survey.survey_remove_unnecessary_decimals">
<t t-set="value_to_format" t-value="choice_data['suggested_answer'].answer_score"/>
<td t-if="question.is_scored_question">
<t t-call="survey.survey_remove_unnecessary_decimals" value_to_format="choice_data['suggested_answer'].answer_score"/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div t-if="comment_lines" t-call="survey.question_result_comments" />
<div t-if="comment_lines"><t t-call="survey.question_result_comments"/></div>
</template>
<template id="question_result_matrix" name="Question: matrix result (matrix)">
<t t-set="graph_data" t-value="question_data['graph_data']"/>
<t t-set="table_data" t-value="question_data['table_data']"/>
<ul class="nav nav-tabs d-print-none" role="tablist">
<li t-if="question_answered" class="nav-item active" >
<a t-att-href="'#survey_graph_question_%d' % question.id"
t-att-aria-controls="'survey_graph_question_%d' % question.id"
class="nav-link active" data-bs-toggle="tab" role="tab">
<i class="fa fa-bar-chart me-1"/>Graph
</a>
</li>
<li class="nav-item">
<a t-att-href="'#survey_data_question_%d' % question.id"
t-att-aria-controls="'survey_data_question_%d' % question.id"
t-attf-class="nav-link #{'active' if not question_answered else ''}" data-bs-toggle="tab" role="tab">
<i class="fa fa-list-alt me-1"/>Data
</a>
</li>
</ul>
<div class="tab-content">
<div t-if="question_answered" role="tabpanel" class="tab-pane active with-3d-shadow with-transitions survey_graph"
t-att-id="'survey_graph_question_%d' % question.id"
@ -432,9 +398,9 @@
data-graph-type= "multi_bar"
t-att-data-graph-data="graph_data">
<!-- canvas element for drawing Multibar chart -->
<canvas/>
<canvas class="mx-auto w-100 h-auto"/>
</div>
<div role="tabpanel" t-attf-class="tab-pane #{'active' if not question_answered else ''}" t-att-id="'survey_data_question_%d' % question.id">
<div role="tabpanel" t-attf-class="tab-pane #{'active' if not question_answered else ''} table-responsive" t-att-id="'survey_data_question_%d' % question.id">
<table class="table table-hover table-sm text-end">
<thead t-if="table_data">
<tr>
@ -450,25 +416,27 @@
<span t-esc="choice_data['row'].value"></span>
</td>
<td class="o_survey_answer" t-foreach="choice_data['columns']" t-as="column_data">
<span t-esc="round(column_data['count'] * 100.0/ (len(question_data['answer_input_done_ids']) or 1), 2)"></span> %
<span class="badge text-bg-primary" t-esc="column_data['count']"></span>
<i t-if="column_data['count']" class="fa fa-filter text-primary filter-add-answer"
t-att-data-question-id="question.id"
t-att-data-row-id="choice_data['row'].id"
t-att-data-answer-id="column_data['suggested_answer'].id" role="img" aria-label="Filter surveys"
title="Only show survey results having selected this answer"></i>
<i t-else="" class="o_survey_answer_matrix_whitespace"/>
<div class="d-flex align-items-center gap-1 justify-content-end">
<span t-esc="round(column_data['count'] * 100.0/ (len(question_data['answer_input_done_ids']) or 1), 2)"></span> %
<span class="badge text-bg-primary" t-esc="column_data['count']"></span>
<i t-if="column_data['count']" class="fa fa-filter text-primary filter-add-answer d-print-none"
data-model-short-key="A"
t-att-data-row-id="choice_data['row'].id"
t-att-data-record-id="column_data['suggested_answer'].id" role="img" aria-label="Filter surveys"
title="Only show survey results having selected this answer"/>
<i t-else="" class="o_survey_answer_matrix_whitespace d-print-none"/>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div t-if="comment_lines" t-call="survey.question_result_comments" />
<div t-if="comment_lines"><t t-call="survey.question_result_comments"/></div>
</div>
</template>
<template id="question_result_comments" name="Question: comments">
<table class="table table-hover table-sm" t-att-id="'survey_table_question_%d' % question.id">
<table class="table table-hover table-sm o_survey_results_table_indexed" t-att-id="'survey_table_question_%d' % question.id">
<thead>
<tr>
<th>#</th>
@ -478,12 +446,9 @@
<tbody>
<tr t-foreach="comment_lines" t-as="input_line">
<td>
<t t-if="no_print_url"><t t-esc="input_line_index + 1"></t></t>
<t t-else="">
<a t-att-href="input_line.user_input_id.get_print_url()">
<t t-esc="input_line_index + 1"></t>
</a>
</t>
<a t-att-href="input_line.user_input_id.get_print_url()">
<t t-esc="input_line_index + 1"></t>
</a>
</td>
<td>
<span t-field="input_line.value_char_box"></span><br/>
@ -494,15 +459,20 @@
</template>
<template id="question_table_pagination" name="Survey: statistics table pagination">
<ul t-att-id="'pagination_%d' % question.id" class="pagination" t-att-data-question_id="question.id" t-att-data-record_limit="page_record_limit">
<t t-if="len(table_data) > page_record_limit">
<t t-set="total" t-value="ceil(len(table_data) / page_record_limit) + 1"/>
<li t-foreach="range(1, total)" t-as="num"
t-att-class="'page-item o_survey_js_results_pagination %s' % ('active' if num == 1 else '')">
<a href="#" class="page-link" t-esc="num"></a>
</li>
</t>
</ul>
<t t-set="non_skipped_answers_count" t-value="len(question_data['answer_input_done_ids'])"/>
<t t-if="non_skipped_answers_count > page_record_limit">
<div class="d-flex justify-content-between d-print-none pagination_wrapper"
t-att-id="'pagination_%d' % question.id" t-att-data-question_id="question.id">
<ul class="pagination mt-2">
<t t-set="total" t-value="ceil(non_skipped_answers_count / page_record_limit) + 1"/>
<li t-foreach="range(1, total)" t-as="num"
t-att-class="'page-item o_survey_js_results_pagination %s' % ('active' if num == 1 else '')">
<a href="#" class="page-link" t-esc="num"></a>
</li>
</ul>
<button class="btn btn-sm btn-primary mx-0 my-3 o_survey_question_answers_show_btn">Show All</button>
</div>
</t>
</template>
<template id="survey_remove_unnecessary_decimals" name="Survey: remove .0">

View file

@ -2,7 +2,7 @@
<odoo>
<data>
<template id="user_input_session" name="Survey User Input Session" inherit_id="web.frontend_layout" primary="True">
<xpath expr="//div[@id='wrapwrap']" position="before">
<xpath expr="//head" position="before">
<!--TODO DBE Fix me : If one day, there is a survey_livechat bridge module, put this in that module-->
<t t-set="no_livechat" t-value="True"/>
</xpath>
@ -12,7 +12,7 @@
if survey.session_question_id and survey.session_question_id.background_image_url
else ('background-image: url(' + survey.background_image_url + ');')
if survey.background_image_url
else '')"/>
else 'background-image: url(\'/survey/static/src/img/survey_background_sample.svg\')')"/>
<attribute name="t-att-class" add="'o_survey_background'"/>
</xpath>
<xpath expr="//head/t[@t-call-assets][last()]" position="after">
@ -30,23 +30,39 @@
<template id="user_input_session_open" name="Survey: Open Session">
<t t-call="survey.user_input_session">
<div class="wrap py-3 min-vh-100 align-items-center justify-content-center d-flex o_survey_session_open o_survey_session_manage"
<div class="o_survey_session_open o_survey_session_manage position-absolute bottom-0 start-0 end-0 d-flex flex-column justify-content-between gap-md-4 mb-md-3 mx-md-4 fs-3 text-white"
t-att-data-survey-access-token="survey.access_token"
t-att-data-survey-id="survey.id"
t-att-data-is-start-screen="True">
<div class="w-75 p-4">
<div class="text-center">
<h1 class="mb-4" t-field="survey.title" />
<h2 class="mb-5 fw-normal">
<span class="text-break">To join: <span class="text-info o_survey_session_copy" t-esc="survey.session_link"/></span>
<input class="o_survey_session_copy_url d-none" type="text" t-att-value="survey.session_link" />
</h2>
<h2 class="fw-normal"><span>Waiting for attendees...</span>
<span class="ms-1 fw-bold o_survey_session_attendees_count" t-esc="survey.session_answer_count" />
</h2>
<div class="o_survey_session_open_header d-flex flex-column flex-md-row flex-grow-1 flex-md-grow-0 justify-content-between gap-4 p-5 rounded-3 bg-black-25">
<div class="o_survey_session_open_title flex-basis-50">
<h1 t-field="survey.title"/>
<div class="o_survey_session_open_description overflow-auto">
<p t-field="survey.description"/>
</div>
</div>
<a role="button"
class="fw-bold fa fa-chevron-right o_survey_session_navigation o_survey_session_navigation_next p-3" />
<div class="d-flex flex-column flex-lg-row gap-4">
<div class="o_survey_session_open_counter d-flex flex-column justify-content-center p-4 rounded-3 bg-black-25 text-center">
<span class="o_survey_session_attendees_count" t-esc="survey.session_answer_count"/>
<p>Waiting for attendees...</p>
</div>
<div class="o_survey_session_qrcode align-self-center ratio ratio-1x1 rounded-3 order-first order-lg-last">
<!-- the value 725 makes the qrcode renders nicely for text from 18 to 53 characters. -->
<img t-att-src="'/report/barcode/QR/%s?width=725&amp;height=725' % quote_plus(survey.session_link)"/>
</div>
</div>
</div>
<div class="o_survey_session_open_link d-flex flex-column flex-md-row align-items-center gap-3 gap-md-0 justify-content-between px-5 py-4 rounded-3 bg-black">
<div class="fs-5 o_survey_session_copy">
<span class="text-info o_survey_session_copy_url" t-out="survey.session_link"/>
<i class="fa fa-copy"/>
</div>
<a role="button" class="o_survey_session_navigation_next btn btn-lg btn-primary w-100 w-md-auto">
<span class="o_survey_session_navigation_next_label">Start</span>
<i class="oi oi-chevron-right"/>
</a>
</div>
</div>
</t>
@ -61,12 +77,13 @@
<template id="user_input_session_manage_content" name="Survey User Input Session Manage">
<t t-set="question" t-value="survey.session_question_id" />
<t t-set="is_scored_question" t-value="any(answer.answer_score for answer in question.suggested_answer_ids)" />
<t t-set="show_bar_chart" t-value="question.question_type in ['simple_choice', 'multiple_choice']" />
<t t-set="show_bar_chart" t-value="question.question_type in ['simple_choice', 'multiple_choice', 'scale']" />
<t t-set="show_text_answers" t-value="question.question_type in ['char_box', 'date', 'datetime'] and not question.save_as_email and not question.save_as_nickname" />
<div class="wrap min-vh-100 align-items-center justify-content-center d-flex flex-column o_survey_session_manage invisible"
t-att-style="'display: none;' if is_rpc_call else ''"
t-att-data-is-rpc-call="is_rpc_call"
t-att-data-survey-id="survey.id"
t-att-data-survey-has-conditional-questions="survey.has_conditional_questions"
t-att-data-attendees-count="survey.session_answer_count"
t-att-data-survey-access-token="survey.access_token"
t-att-data-timer="survey.session_question_start_time.isoformat()"
@ -79,6 +96,7 @@
t-att-data-answers-validity="answers_validity"
t-att-data-is-first-question="is_first_question"
t-att-data-is-last-question="is_last_question"
t-att-data-survey-last-triggering-answers="survey_last_triggering_answers"
t-att-data-current-screen="'question' if is_scored_question else 'userInputs'"
t-att-data-show-bar-chart="show_bar_chart"
t-att-data-show-text-answers="show_text_answers"
@ -86,8 +104,8 @@
t-att-data-is-session-closed="is_session_closed">
<div t-if="not is_session_closed" class="o_survey_question_header flex-wrap px-3 w-100 d-flex justify-content-between align-items-center position-absolute">
<h3>
<span>To join: <span class="text-info o_survey_session_copy" t-esc="survey.session_link"/></span>
<input class="o_survey_session_copy_url d-none" type="text" t-att-value="survey.session_link" />
<span>To join: <span class="text-info o_survey_session_copy o_survey_session_copy_url" t-esc="survey.session_link"/></span>
<input class="d-none" type="text" t-att-value="survey.session_link" />
</h3>
<h1 t-if="question.is_time_limited" class="o_survey_timer_container">
<span class="o_survey_timer d-inline-block"/>
@ -96,22 +114,25 @@
<div t-if="show_bar_chart or show_text_answers">
<div class="progress" title="Attendees are answering the question...">
<div class="progress-bar o_survey_session_progress_small fw-bold"
style="overflow: visible" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
style="overflow: visible" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" aria-label="Progress bar">
<span class="px-2">0 / <t t-esc="survey.session_answer_count" /></span>
</div>
</div>
</div>
</div>
</div>
<div class="container px-4 pb-3 pt96 d-flex flex-column o_survey_session_manage_container">
<div class="o_survey_session_description_done d-none">
<h1>Thank you!</h1>
<div class="px-sm-4 pb-3 pt96 d-flex flex-column o_survey_session_manage_container">
<div class="o_survey_session_description_done d-none o_container_small">
<h1 class="fs-2">Thank you!</h1>
<div t-field="survey.description_done"/>
</div>
<a role="button"
class="fw-bold fa fa-chevron-right o_survey_session_navigation o_survey_session_navigation_next p-3" />
class="o_survey_session_navigation o_survey_session_navigation_next p-2 bg-light">
<span class="o_survey_session_navigation_next_label me-2 fw-bold d-none d-md-inline"/>
<i class="fw-bold oi oi-chevron-right"/>
</a>
<a role="button"
class="fw-bold fa fa-chevron-left o_survey_session_navigation o_survey_session_navigation_previous p-3" />
class="fw-bold oi oi-chevron-left o_survey_session_navigation o_survey_session_navigation_previous p-3" />
<div class="o_survey_session_results flex-column flex-grow-1 mx-5">
<div class="row">
<div class="col-lg-12"><h1 t-esc="question.title"></h1></div>
@ -136,27 +157,28 @@
</span>
</h2>
<div class="progress">
<div class="progress-bar fw-bold" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
<div class="progress-bar fw-bold" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" aria-label="Progress bar"></div>
</div>
<fieldset disabled="disabled" class="mt-5" t-if="question.question_type == 'matrix'" t-call="survey.question_container">
<t t-set="hide_question_title" t-value="true" />
<t t-set="answer" t-value="env['survey.user_input']" />
<t t-set="survey_form_readonly" t-value="True"/>
<fieldset disabled="disabled" class="mt-5" t-if="question.question_type == 'matrix'">
<t t-call="survey.question_container"
hide_question_title="True"
answer="env['survey.user_input']"
survey_form_readonly="True"/>
</fieldset>
</div>
</div>
</div>
<div class="o_survey_session_leaderboard w-100 flex-column flex-grow-1" style="display: none;">
<div class="o_survey_session_leaderboard w-100 flex-column flex-grow-1 min-vw-75 d-none" style="max-height: 80vh; min-width: 50vw">
<!--Set question to false to avoid background miss match when no question are displayed.-->
<t t-set="question" t-value="False"/>
<div class="d-flex">
<h1 class="o_survey_session_leaderboard_title flex-grow-1">
<div class="d-flex flex-wrap">
<h1 class="o_survey_session_leaderboard_title flex-grow-1 me-4 ms-1">
<span t-if="is_last_question">Final Leaderboard</span>
<span t-else="">Leaderboard</span>
</h1>
<div t-att-class="'o_survey_leaderboard_buttons fw-bold %s' % 'd-none' if not is_last_question else ''">
<a href="#" role="button" class="o_survey_session_close btn btn-primary me-4"><i class="fa fa-close"/> Close</a>
<a href="#" role="button" class="o_survey_session_close btn btn-primary" t-att-data-show-results="True"><i class="fa fa-bar-chart"/> Results</a>
<div t-att-class="'o_survey_leaderboard_buttons fw-bold %s' % 'd-none' if not is_last_question else 'ms-2'">
<a href="#" role="button" class="o_survey_session_close btn btn-primary mt-1"><i class="fa fa-close"/> Close</a>
<a href="#" role="button" class="o_survey_session_close btn btn-primary mt-1" t-att-data-show-results="True"><i class="fa fa-bar-chart"/> Results</a>
</div>
</div>
<div class="justify-content-center d-flex flex-column flex-grow-1 mt-5 mb-5 pb-5 o_survey_session_leaderboard_container"/>

View file

@ -13,18 +13,19 @@
('email', 'ilike', self)]"/>
<field name="partner_id"/>
<field name="survey_id"/>
<filter name="completed" string="Completed" domain="[('state', '=', 'done')]"/>
<filter string="In Progress" name="in_progress" domain="[('state', '=', 'in_progress')]"/>
<filter string="New" name="new" domain="[('state', '=', 'new')]"/>
<filter string="In Progress" name="in_progress" domain="[('state', '=', 'in_progress')]"/>
<filter name="completed" string="Completed" domain="[('state', '=', 'done')]"/>
<separator/>
<filter string="Quizz passed" name="scoring_success" domain="[('scoring_success','=', True)]"/>
<filter string="Quiz passed" name="scoring_success" domain="[('scoring_success','=', True)]"/>
<separator/>
<filter string="Tests Only" name="test" domain="[('test_entry','=', True)]"/>
<filter string="Exclude Tests" name="not_test" domain="[('test_entry','=', False)]"/>
<group expand="0" string="Group By">
<group>
<filter name="group_by_survey" string="Survey" domain="[]" context="{'group_by': 'survey_id'}"/>
<filter string="Email" name="group_by_email" domain="[]" context="{'group_by': 'email'}"/>
<filter string="Partner" name="group_by_partner" domain="[]" context="{'group_by': 'partner_id'}"/>
<filter string="Language" name="group_by_lang" domain="[]" context="{'group_by': 'lang_id'}"/>
</group>
</search>
</field>
@ -37,8 +38,8 @@
<form string="Survey User inputs" create="false">
<header>
<button name="action_resend" string="Resend Invitation" type="object" class="oe_highlight"
attrs="{'invisible': ['|', ('state', '=', 'done'), '&amp;', ('partner_id', '=', False), ('email', '=', False)]}"/>
<button name="action_print_answers" states="done" string="Print" type="object" class="oe_highlight"/>
invisible="state == 'done' or not partner_id and not email"/>
<button name="action_print_answers" invisible="state != 'done'" string="Print" type="object" class="oe_highlight"/>
<field name="state" widget="statusbar"/>
</header>
<sheet>
@ -47,28 +48,28 @@
<button name="action_redirect_to_attempts"
type="object"
class="oe_stat_button"
attrs="{'invisible': [('attempts_count', '=', 1)]}"
invisible="attempts_count == 1"
icon="fa-files-o">
<field string="Attempts" name="attempts_count" widget="statinfo"/>
</button>
</div>
<field name="test_entry" invisible="1"/>
<widget name="web_ribbon" title="Test Entry" bg_color="bg-info"
attrs="{'invisible': [('test_entry', '!=', True)]}"/>
<widget name="web_ribbon" title="Failed" bg_color="bg-danger"
attrs="{'invisible': ['|', '|', ('test_entry', '=', True), ('scoring_type', '=', 'no_scoring'), ('scoring_success', '=', True)]}"/>
<widget name="web_ribbon" title="Test Entry" bg_color="text-bg-info"
invisible="not test_entry"/>
<widget name="web_ribbon" title="Failed" bg_color="text-bg-danger"
invisible="test_entry or scoring_type == 'no_scoring' or scoring_success"/>
<widget name="web_ribbon" title="Passed"
attrs="{'invisible': ['|', '|', ('test_entry', '=', True), ('scoring_type', '=', 'no_scoring'), ('scoring_success', '=', False)]}"/>
invisible="test_entry or scoring_type == 'no_scoring' or not scoring_success"/>
<group col="2">
<group>
<field name="survey_id"/>
<field name="create_date"/>
<field name="deadline" attrs="{'invisible': [('state', '=', 'done'), ('deadline', '=', False)]}"/>
<field name="deadline" invisible="state == 'done' and not deadline"/>
<field name="is_attempts_limited" invisible="1"/>
<label for="attempts_number" string="Attempt n°" attrs="{'invisible': ['|', ('is_attempts_limited', '=', False), '|', ('test_entry', '=', True), ('state', '!=', 'done')]}"/>
<div attrs="{'invisible': ['|', ('is_attempts_limited', '=', False), '|', ('test_entry', '=', True), ('state', '!=', 'done')]}" class="d-inline-flex">
<label for="attempts_number" string="Attempt n°" invisible="not is_attempts_limited or test_entry or state != 'done'"/>
<div invisible="not is_attempts_limited or test_entry or state != 'done'" class="d-inline-flex">
<field name="attempts_number" nolabel="1"/>
/
/
<field name="attempts_limit" nolabel="1"/>
</div>
<field name="test_entry" groups="base.group_no_one"/>
@ -76,8 +77,8 @@
<group>
<field name="scoring_type" invisible="1"/>
<field name="scoring_success" invisible="1"/>
<label for="scoring_percentage" string="Score" attrs="{'invisible': [('scoring_type', '=', 'no_scoring')]}"/>
<div attrs="{'invisible': [('scoring_type', '=', 'no_scoring')]}" class="d-inline-flex">
<label for="scoring_percentage" string="Score" invisible="scoring_type == 'no_scoring'"/>
<div invisible="scoring_type == 'no_scoring'" class="d-inline-flex">
<field name="scoring_percentage" nolabel="1"/>
<span>%</span>
</div>
@ -87,10 +88,10 @@
</group>
</group>
<notebook>
<page string="Answers">
<field name="user_input_line_ids" mode="tree" attrs="{'readonly': True}" no_label="1">
<tree decoration-muted="skipped == True">
<field name="question_sequence" invisible="1"/>
<page string="Answers" name="page_answers">
<field name="user_input_line_ids" mode="list" readonly="True" no_label="1">
<list decoration-muted="skipped == True">
<field name="question_sequence" column_invisible="True"/>
<field name="create_date" optional="hidden"/>
<field name="page_id" optional="hidden"/>
<field name="question_id"/>
@ -99,25 +100,21 @@
<field name="display_name" string="Answer"/>
<field name="answer_is_correct"/>
<field name="answer_score" sum="Score"/>
</tree>
</list>
</field>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="activity_ids"/>
<field name="message_ids"/>
</div>
<chatter/>
</form>
</field>
</record>
<record id="survey_user_input_view_tree" model="ir.ui.view">
<field name="name">survey.user_input.view.tree</field>
<field name="name">survey.user_input.view.list</field>
<field name="model">survey.user_input</field>
<field name="arch" type="xml">
<tree string="Survey User inputs" decoration-muted="test_entry == True" create="false">
<list string="Survey User inputs" decoration-muted="test_entry == True" create="false">
<field name="create_date"/>
<field name="survey_id"/>
<field name="nickname" optional="hide"/>
@ -125,14 +122,14 @@
<field name="email" optional="show"/>
<field name="attempts_number"/>
<field name="deadline"/>
<field name="test_entry" invisible="True"/>
<field name="test_entry" column_invisible="True"/>
<field name="scoring_success"/>
<field name="scoring_percentage"/>
<field name="state" widget="badge"
decoration-success="state == 'done'"
decoration-warning="state == 'new'"
decoration-info="state == 'in_progress'"/>
</tree>
decoration-info="state == 'new'"
decoration-warning="state == 'in_progress'"/>
</list>
</field>
</record>
@ -141,28 +138,13 @@
<field name="model">survey.user_input</field>
<field name="arch" type="xml">
<kanban create="false" group_create="false">
<field name="survey_id"/>
<field name="create_date"/>
<field name="partner_id"/>
<field name="email"/>
<field name="state"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_global_click">
<div class="o_kanban_record_top">
<div class="o_kanban_record_headings">
<strong class="o_kanban_record_title"><t t-esc="record.survey_id.value"/></strong>
</div>
</div>
<div class="o_kanban_record_bottom">
<div class="oe_kanban_bottom_left">
<field name="create_date"/>
</div>
<div class="oe_kanban_bottom_right mr4">
<field name="state" widget="label_selection" options="{'classes': {'new': 'default', 'done': 'success', 'in_progress':'warning'}}"/>
</div>
</div>
</div>
<t t-name="card">
<field name="survey_id" class="fw-bold fs-5 mb-1"/>
<footer class="pt-0">
<field name="create_date"/>
<field name="state" widget="label_selection" options="{'classes': {'new': 'default', 'done': 'success', 'in_progress':'warning'}}" class="ms-auto"/>
</footer>
</t>
</templates>
</kanban>
@ -170,9 +152,10 @@
</record>
<record model="ir.actions.act_window" id="action_survey_user_input">
<field name="name">Participations</field>
<field name="name">Participants</field>
<field name="res_model">survey.user_input</field>
<field name="view_mode">tree,kanban,form</field>
<field name="domain">[('survey_id.survey_type', 'in', ('assessment', 'custom', 'live_session', 'survey'))]</field>
<field name="view_mode">list,kanban,form</field>
<field name="view_id" ref="survey_user_input_view_tree"></field>
<field name="search_view_id" ref="survey_user_input_view_search"/>
<field name="context">{'search_default_group_by_survey': True}</field>
@ -201,23 +184,23 @@
<field name="answer_score" groups="base.group_no_one"/>
</group>
<group>
<field name="value_char_box" colspan='2' attrs="{'invisible': [('answer_type','!=','char_box')]}"/>
<field name="value_numerical_box" colspan='2' attrs="{'invisible': [('answer_type','!=','numerical_box')]}"/>
<field name="value_date" colspan='2' attrs="{'invisible': [('answer_type','!=','date')]}"/>
<field name="value_datetime" colspan='2' attrs="{'invisible': [('answer_type','!=','datetime')]}"/>
<field name="value_text_box" colspan='2' attrs="{'invisible': [('answer_type','!=','text_box')]}"/>
<field name="value_char_box" colspan='2' invisible="answer_type != 'char_box'"/>
<field name="value_numerical_box" colspan='2' invisible="answer_type != 'numerical_box'"/>
<field name="value_date" colspan='2' invisible="answer_type != 'date'"/>
<field name="value_datetime" colspan='2' invisible="answer_type != 'datetime'"/>
<field name="value_text_box" colspan='2' invisible="answer_type != 'text_box'"/>
<field name="matrix_row_id" colspan='2' />
<field name="suggested_answer_id" colspan='2' attrs="{'invisible': [('answer_type','!=','suggestion')]}"/>
<field name="suggested_answer_id" colspan='2' invisible="answer_type != 'suggestion'"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="survey_response_line_view_tree" model="ir.ui.view">
<field name="name">survey.user_input.line.view.tree</field>
<field name="name">survey.user_input.line.view.list</field>
<field name="model">survey.user_input.line</field>
<field name="arch" type="xml">
<tree string="Survey Answer Line" create="false">
<list string="Survey Answer Line" create="false">
<field name="survey_id"/>
<field name="user_input_id"/>
<field name="question_id"/>
@ -225,7 +208,7 @@
<field name="answer_type"/>
<field name="skipped"/>
<field name="answer_score" groups="base.group_no_one"/>
</tree>
</list>
</field>
</record>
<record id="survey_user_input_line_view_search" model="ir.ui.view">
@ -235,8 +218,9 @@
<search string="Search User input lines">
<field name="user_input_id"/>
<field name="survey_id"/>
<group expand="1" string="Group By">
<group>
<filter name="group_by_survey" string="Survey" domain="[]" context="{'group_by':'survey_id'}"/>
<filter name="group_by_lang" string="Language" domain="[]" context="{'group_by':'lang_id'}"/>
<filter name="group_by_user_input" string="User Input" domain="[]" context="{'group_by':'user_input_id'}"/>
</group>
</search>
@ -246,7 +230,8 @@
<record id="survey_user_input_line_action" model="ir.actions.act_window">
<field name="name">Detailed Answers</field>
<field name="res_model">survey.user_input.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('survey_id.survey_type', 'in', ('assessment', 'custom', 'live_session', 'survey'))]</field>
<field name="view_mode">list,form</field>
<field name="search_view_id" ref="survey_user_input_line_view_search"/>
<field name="context">{'search_default_group_by_survey': True, 'search_default_group_by_user_input': True}</field>
<field name="help" type="html">
@ -256,7 +241,7 @@
</field>
</record>
<menuitem name="Participations"
<menuitem name="Participants"
id="menu_survey_type_form1"
action="action_survey_user_input"
parent="menu_surveys"