Initial commit: Core packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:45 +02:00
commit 12c29a983b
9512 changed files with 8379910 additions and 0 deletions

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo><data>
<record id="gamification_badge_form_view_simplified" model="ir.ui.view">
<field name="name">gamification.badge.form.view.simplified</field>
<field name="model">gamification.badge</field>
<field name="priority">100</field>
<field name="arch" type="xml">
<form string="Badge">
<sheet>
<div class="oe_button_box" name="button_box"/>
<field name="image_1920" widget="image" class="oe_avatar" options="{'preview_image': 'image_128'}"/>
<div class="oe_title">
<label for="name"/>
<h1>
<field name="name" placeholder="e.g. Problem Solver"/>
</h1>
</div>
<field name="description" placeholder="e.g. No one can solve challenges like you do"/>
<group string="Rewards for challenges">
<field name="level"/>
</group>
</sheet>
</form>
</field>
</record>
</data></odoo>

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo><data>
<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="context">{'search_default_scoring_success': 1}</field>
</record>
<record id="res_partner_view_form" model="ir.ui.view">
<field name="name">res.partner.view.form.inherit.survey</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<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)]}">
<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>
</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)]}">
<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>
</div>
</button>
</xpath>
</field>
</record>
</data></odoo>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Main menu -->
<menuitem name="Surveys"
id="menu_surveys"
sequence="130"
groups="group_survey_user"
web_icon="survey,static/description/icon.svg"/>
<!-- Parent menus -->
<menuitem name="Questions &amp; Answers"
id="survey_menu_questions"
parent="menu_surveys"
sequence="90"/>
</data>
</odoo>

View file

@ -0,0 +1,368 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- QUESTIONS -->
<record model="ir.ui.view" id="survey_question_form">
<field name="name">Form view for survey question</field>
<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_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"/>
<sheet>
<div class="float-end d-flex flex-column text-center" attrs="{'invisible': [('is_page', '=', False)]}">
<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)]}"/>
<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')]}">
<field name="random_questions_count"/>
</group>
<group attrs="{'invisible': [('is_page', '=', True)]}">
<group>
<field name="question_type" widget="radio" attrs="{'required': [('is_page', '=', False)]}" />
</group>
<group>
<div class="mx-lg-auto w-lg-50 d-none d-sm-block o_preview_questions" colspan="2">
<!-- Multiple choice: only one answer -->
<div attrs="{'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>
<div class="o_preview_questions_choice mb-2"><i class="fa fa-dot-circle-o fa-lg me-2"/>answer</div>
<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"
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>
<!-- Multiple Lines Text Zone -->
<div attrs="{'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')]}">
<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')]}">
<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')]}">
<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')]}">
<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 class="row o_matrix_head">
<div class="col-3"></div>
<div class="col-3">ans</div>
<div class="col-3">ans</div>
<div class="col-3">ans</div>
</div>
<div class="row o_matrix_row">
<div class="col-3">Row1</div>
<div class="col-3"><i class="fa fa-circle-o fa-lg" role="img" aria-label="Not checked" title="Not checked"/></div>
<div class="col-3"><i class="fa fa-dot-circle-o fa-lg" role="img" aria-label="Checked" title="Checked"/></div>
<div class="col-3"><i class="fa fa-circle-o fa-lg" role="img" aria-label="Not checked" title="Not checked"/></div>
</div>
<div class="row o_matrix_row">
<div class="col-3">Row2</div>
<div class="col-3"><i class="fa fa-circle-o fa-lg" role="img" aria-label="Not checked" title="Not checked"/></div>
<div class="col-3"><i class="fa fa-circle-o fa-lg" role="img" aria-label="Not checked" title="Not checked"/></div>
<div class="col-3"><i class="fa fa-dot-circle-o fa-lg" role="img" aria-label="Checked" title="Checked"/></div>
</div>
<div class="row o_matrix_row">
<div class="col-3">Row3</div>
<div class="col-3"><i class="fa fa-dot-circle-o fa-lg" role="img" aria-label="Checked" title="Checked"/></div>
<div class="col-3"><i class="fa fa-circle-o fa-lg" role="img" aria-label="Not checked" title="Not checked"/></div>
<div class="col-3"><i class="fa fa-circle-o fa-lg" role="img" aria-label="Not checked" title="Not checked"/></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']),
]}">
<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"/>
<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')]}"/>
</group>
<group attrs="{'invisible': ['|', ('scoring_type', '=', 'no_scoring'), ('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>
</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>
<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>
</page>
<page string="Description" name="survey_description">
<field name="description" widget="html"
placeholder="e.g. Guidelines, instructions, picture, ... to help attendees answer"/>
</page>
<page string="Options" name="options" attrs="{'invisible': [('is_page', '=', True)]}">
<group>
<group string="Answers">
<!-- 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)]}"/>
<field name="validation_error_msg" attrs="{
'invisible': [('validation_required', '=', False)]}"
placeholder="The answer you entered is not valid."/>
<field name="matrix_subtype" attrs="{'invisible':[('question_type','not in',['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:"/>
<field name='comment_count_as_answer'
attrs="{'invisible': ['|', ('question_type', 'not in', ['simple_choice','multiple_choice', 'matrix']), ('comments_allowed', '=', False)]}"/>
</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>
</group>
<group>
<group string="Constraints">
<field name="constr_mandatory" string="Mandatory Answer"/>
<field name="constr_error_msg"
attrs="{'invisible': [('constr_mandatory', '=', False)]}"
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="time_limit" nolabel="1" class="oe_inline"
attrs="{'invisible': [('is_time_limited', '=', False)]}" />
<span attrs="{'invisible': [('is_time_limited', '=', False)]}"> seconds</span>
</div>
</group>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="survey_question_tree">
<field name="name">Tree 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"/>
<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>
</record>
<record model="ir.ui.view" id="survey_question_search">
<field name="name">Search view for survey question</field>
<field name="model">survey.question</field>
<field name="arch" type="xml">
<search string="Search Question">
<field name="title"/>
<field name="survey_id" string="Survey"/>
<field name="question_type" string="Type"/>
<group expand="1" string="Group By">
<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>
</search>
</field>
</record>
<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="search_view_id" ref="survey_question_search"/>
<field name="context">{'search_default_group_by_page': True}</field>
<field name="domain">[('is_page', '=', False)]</field>
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">
No Questions yet!
</p><p>
Come back once you have added questions to your Surveys.
</p>
</field>
</record>
<!-- LABELS -->
<record id="survey_question_answer_view_tree" model="ir.ui.view">
<field name="name">survey.question.answer.view.tree</field>
<field name="model">survey.question.answer</field>
<field name="arch" type="xml">
<tree string="Survey Label" create="false">
<field name="sequence" widget="handle"/>
<field name="question_id"/>
<field name="matrix_question_id"/>
<field name="value"/>
<field name="answer_score" groups="base.group_no_one"/>
</tree>
</field>
</record>
<record id="survey_question_answer_view_form" model="ir.ui.view">
<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">
<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="value_image"/>
</group>
<group>
<field name="value"/>
<field name="matrix_question_id" attrs="{'invisible': [('question_type', '!=', 'matrix')]}"/>
<field name="sequence"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="survey_question_answer_view_search" model="ir.ui.view">
<field name="name">survey.question.answer.view.search</field>
<field name="model">survey.question.answer</field>
<field name="arch" type="xml">
<search string="Search Label">
<field name="question_id"/>
<group expand="1" string="Group By">
<filter name="group_by_question" string="Question" domain="[]" context="{'group_by':'question_id'}"/>
</group>
</search>
</field>
</record>
<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="search_view_id" ref="survey_question_answer_view_search"/>
<field name="context">{'search_default_group_by_question': True}</field>
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">
No survey labels found
</p>
</field>
</record>
<menuitem name="Questions"
id="menu_survey_question_form1"
action="action_survey_question_form"
parent="survey_menu_questions"
sequence="2"/>
<menuitem name="Suggested Values"
id="menu_survey_label_form1"
action="survey_question_answer_action"
parent="survey_menu_questions"
sequence="3"/>
<menuitem name="Detailed Answers"
id="menu_survey_response_line_form"
action="survey_user_input_line_action"
parent="survey_menu_questions"
sequence="4"/>
</data>
</odoo>

View file

@ -0,0 +1,122 @@
<?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

@ -0,0 +1,33 @@
<?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

@ -0,0 +1,468 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="survey_survey_view_form" model="ir.ui.view">
<field name="name">survey.survey.view.form</field>
<field name="model">survey.survey</field>
<field name="arch" type="xml">
<form string="Survey" class="o_survey_form">
<field name="id" invisible="1"/>
<field name="session_state" invisible="1"/>
<field name="question_ids" invisible="1"/>
<header>
<button name="action_send_survey" string="Share" type="object" class="oe_highlight" attrs="{'invisible': [('active', '=', False)]}"/>
<button name="action_result_survey" string="See results" type="object" class="oe_highlight"
attrs="{'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)]}" />
<button name="action_open_session_manager" string="Open Session Manager" type="object" class="d-none d-sm-block"
attrs="{'invisible': [('session_state', '=', False)]}" />
<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)]}"/>
</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')]}"
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)]}"
icon="fa-trophy">
<field string="Certified" name="success_count" widget="statinfo"/>
</button>
<button name="action_survey_user_input_completed"
type="object"
class="oe_stat_button"
icon="fa-check-square-o">
<field string="Participations" name="answer_done_count" widget="statinfo"/>
</button>
</div>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<field name="background_image" widget="image" class="oe_avatar"/>
<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"/>
</h1>
</div>
<group>
<group>
<field name="user_id" domain="[('share', '=', False)]" widget="many2one_avatar_user"/>
<field name="active" invisible="1"/>
<field name="has_conditional_questions" invisible="1"/>
</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="sequence" widget="handle"/>
<field name="title" widget="survey_description_page"/>
<field name="background_image" invisible="1"/>
<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="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"/>
<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>
</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')]}"/>
</group>
<group string="Participants" name="participants">
<field name="access_mode"/>
<field name="users_login_required"/>
<label for="is_attempts_limited" string="Limit Attempts"
attrs="{'invisible': ['&amp;', ('access_mode', '=', 'public'), ('users_login_required', '=', False)]}"/>
<div class="o_checkbox_optional_field"
attrs="{'invisible': ['&amp;', ('access_mode', '=', 'public'), ('users_login_required', '=', False)]}">
<field name="is_attempts_limited" nolabel="1"/>
<div attrs="{'invisible': [('is_attempts_limited', '=', False)]}">
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">
<field name="is_time_limited" nolabel="1"/>
<div attrs="{'invisible': [('is_time_limited', '=', False)]}">
<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">
<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>
<field name="certification_mail_template_id"
placeholder="Pick a Template..."
attrs="{'invisible': [('certification', '=', False)]}"/>
<label for="certification_give_badge"
attrs="{'invisible': ['|', ('certification', '=', False), ('users_login_required', '=', False)]}"/>
<div class="float-start o_checkbox_optional_field"
attrs="{'invisible': ['|', ('certification', '=', False), ('users_login_required', '=', False)]}">
<field name="certification_give_badge"/>
<div attrs="{'invisible': [('certification_give_badge', '=', False)]}">
<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)]"
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)]}"
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">
<field name="session_code" />
<field name="session_link" widget="CopyClipboardChar" />
<field name="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>
</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>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="activity_ids"/>
<field name="message_ids"/>
</div>
</form>
</field>
</record>
<record id="survey_survey_view_tree" model="ir.ui.view">
<field name="name">survey.survey.view.tree</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"/>
<field name="title"/>
<button name="certification" type="button" disabled="disabled"
icon="fa-trophy" title="Certification" aria-label="Certification"
attrs="{'invisible': [('certification', '=', False)]}"/>
<field name="user_id" widget="many2one_avatar_user"/>
<field name="answer_duration_avg" widget="float_time"/>
<field name="answer_count"/>
<field name="answer_done_count" optional="hide"/>
<field name="success_count" optional="hide"/>
<field name="success_ratio"/>
<field name="answer_score_avg"/>
<!-- Tweak as icons aren't directly supported in xml -->
</tree>
</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">
<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"/>
<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 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="user_id" widget="many2one_avatar_user"
options="{'display_avatar_name': True}"/>
-
<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"/>
<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 />
<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">
<a type="object"
name="action_survey_user_input"
class="fw-bold">
<field name="answer_count"/><br />
<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">
<a type="object"
name="action_survey_user_input_completed"
class="fw-bold">
<field name="answer_done_count"/><br />
<span class="text-muted">Completed</span>
</a>
</div>
<div t-if="!selection_mode" class="col-lg-1 col-sm-4 col-6 py-0 my-2"
name="o_survey_kanban_card_section_success">
<a t-if="record.scoring_type.raw_value != 'no_scoring'"
type="object"
name="action_survey_user_input_certified"
class="fw-bold">
<field name="success_ratio" widget="progressbar" class="d-block"/>
<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">
<button name="action_send_survey"
string="Share" type="object"
class="btn btn-secondary border"
attrs="{'invisible': [('active', '=', False)]}">
Share
</button>
<button name="action_test_survey"
string="Test" type="object"
class="btn btn-secondary border"
attrs="{'invisible': [('active', '=', False)]}">
Test
</button>
<button name="action_result_survey"
string="See results" type="object"
class="btn btn-secondary border"
attrs="{'invisible': [('active', '=', False)]}">
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)]}">
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)]}">
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">
<field name="activity_ids" widget="kanban_activity"/>
</div>
</div>
</templates>
</kanban>
</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="Question &amp; Pages" name="question_and_page_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="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"/>
<filter invisible="1" string="Today Activities" name="activities_today"
domain="[('my_activity_date_deadline', '=', context_today().strftime('%Y-%m-%d'))]"/>
<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">
<filter string="Responsible" name="group_by_responsible"
context="{'group_by': 'user_id'}"/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_survey_form">
<field name="name">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>
</record>
<record id="survey_survey_view_graph" model="ir.ui.view">
<field name="name">survey.survey.view.graph</field>
<field name="model">survey.survey</field>
<field name="arch" type="xml">
<graph>
<field type="measure" name="color" invisible="1"/>
</graph>
</field>
</record>
<record id="survey_survey_view_pivot" model="ir.ui.view">
<field name="name">survey.survey.view.pivot</field>
<field name="model">survey.survey</field>
<field name="arch" type="xml">
<pivot>
<field type="measure" name="color" invisible="1"/>
</pivot>
</field>
</record>
<menuitem name="Surveys" id="menu_survey_form" action="action_survey_form" parent="menu_surveys" sequence="1"/>
</data>
</odoo>

View file

@ -0,0 +1,641 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<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">
<!--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>
<xpath expr="//div[@id='wrapwrap']" position="attributes">
<attribute name="t-att-style"
add="(('background-image: url(' + question.background_image_url + ');')
if question and question.background_image_url
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
else '')"/>
<attribute name="t-att-class"
add="(('o_survey_background o_survey_background_shadow')
if (question and question.background_image_url)
or (page and page.background_image_url)
or (survey and survey.background_image_url)
else 'o_survey_background')"
separator=" "/>
</xpath>
<xpath expr="//head/t[@t-call-assets][last()]" position="after">
<t t-call-assets="survey.survey_assets" lazy_load="True"/>
</xpath>
<xpath expr="//header" position="before">
<t t-set="no_header" t-value="True"/>
<t t-set="no_footer" t-value="True"/>
</xpath>
<xpath expr="//header" position="after">
<div id="wrap" class="oe_structure oe_empty"/>
</xpath>
<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.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-set="page_number" t-value="page_ids.index(question.id)"/>
</t>
</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>
<div class="o_survey_navigation_wrapper d-inline-block" t-call="survey.survey_navigation">
</div>
</div>
</div>
</xpath>
</template>
<!-- Main survey template -->
<template id="survey_page_fill" name="Survey: main page (take survey)">
<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">
<t t-call="survey.survey_fill_header" />
<t t-call="survey.survey_fill_form" />
</div>
</div>
</t>
</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>
</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>
</template>
<template id="survey_fill_form" name="Survey: main page content">
<t t-set="survey_form_readonly" t-value="answer.state == 'done'"/>
<t t-set="background_image_url"
t-value="question.background_image_url
if question else page.background_image_url
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"
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"
t-att-data-session-in-progress="answer.is_session_answer"
t-att-data-is-start-screen="answer.state == 'new'"
t-att-data-readonly="survey_form_readonly"
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-questions-layout="survey.questions_layout"
t-att-data-triggered-questions-by-answer="json.dumps(triggered_questions_by_answer)"
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()"/>
<input type="hidden" name="token" t-att-value="answer.access_token" />
<div class="o_survey_error alert alert-danger d-none" role="alert">
<p>There was an error during the validation of the survey.</p>
</div>
<div class="o_survey_form_content w-100">
<t t-if="answer.state == 'new'" t-call="survey.survey_fill_form_start"/>
<t t-elif="answer.state == 'in_progress'" t-call="survey.survey_fill_form_in_progress" />
<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"/>
<t t-if="answer.is_session_answer">
<div class="fw-bold">
The session will begin automatically when the host starts.
</div>
</t>
<t t-else="">
<div t-if="survey.is_time_limited">
<p>
<span t-if="not survey.certification">Time limit for this survey: </span>
<span t-else="">Time limit for this certification: </span>
<span class="fw-bold text-danger" t-field="survey.time_limit" t-options="{'widget': 'duration', 'unit': 'minute'}"></span>
</p>
</div>
<button type="submit" value="start" class="btn btn-primary btn-lg disabled">
<t t-if="survey.certification">
Start Certification
</t>
<t t-else="">
Start Survey
</t>
</button>
<span class="o_survey_enter fw-bold text-muted ms-2 d-none d-md-inline">or press Enter</span>
</t>
</div>
</div>
</template>
<template id="survey_fill_form_in_progress" name="Survey: form with questions">
<div class="o_survey_form_content_data d-none"
t-att-data-question-time-limit-reached="answer.question_time_limit_reached"
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-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"/>
</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>
</div>
</t>
<t t-if="survey.questions_layout == 'page_per_section'">
<h2 t-field='page.title' class="o_survey_title pb16 text-break" />
<div t-field='page.description' class="oe_no_empty text-break"/>
<input type="hidden" name="page_id" t-att-value="page.id" />
<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 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>
</button>
<span class="fw-bold text-muted ms-2 d-none d-md-inline" id="enter-tooltip"> or press 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)" />
<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 ''}">
<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)">
<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>
</t>
<t t-else="">
<div class="mt-5">
<t t-call="survey.question_container"/>
</div>
<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-else="">Continue</t>
</button>
<span class="fw-bold text-muted ms-2 d-none d-md-inline">
<span id="enter-tooltip">or press Enter</span>
</span>
</div>
</div>
</t>
</div>
</template>
<!-- Finished (taken and finished) survey page -->
<template id="survey_fill_form_done" name="Survey: finished">
<div class="wrap">
<div class="o_survey_finished mt32 mb32">
<h1>Thank you!</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>
<div t-if="survey.certification" class="mt16 mb16">
<a role="button"
class="btn btn-primary btn-lg"
t-att-href="'/survey/%s/get_certification' % survey.id">
<i class="fa fa-fw fa-trophy" role="img" aria-label="Download certification" title="Download certification"/>
Download certification
</a>
</div>
</t>
<t t-else="">
<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>
</div>
<div class="col-6 text-center" t-if="survey.certification_give_badge and answer.scoring_success">
<img t-att-src="'/web/image/gamification.badge/%s/image_128' % survey.certification_badge_id.id"/>
<div>You received the badge <span class="fw-bold" t-esc="survey.certification_badge_id.name"/>!</div>
</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>
<!-- Question widgets -->
<template id="question_container" name="Survey: question container">
<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))"/>
<t t-set="answer_lines" t-value="answer.user_input_line_ids.filtered(lambda line: line.question_id == question)"/>
<!--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'"/>
<!-- Extra 'right' margin is added on layouts that are not "page_per_question" to align with choices questions, since all choices have a me-2 class (pixel perfect yay...) -->
<t t-set="extra_right_margin" t-value="survey.questions_layout != 'page_per_question' and question.question_type not in ['simple_choice', 'multiple_choice']"/>
<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">
<div class="mb-4">
<h3 t-if="not hide_question_title">
<span t-field='question.title' class="text-break" />
<span t-if="question.constr_mandatory" class="text-danger">*</span>
</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>
</div>
</template>
<template id="question_text_box" name="Question: free text box">
<div class="o_survey_comment_container 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>
</div>
</template>
<template id="question_char_box" name="Question: text box">
<div class="o_survey_comment_container p-0">
<input t-att-type="'email' if question.validation_email else 'text'"
class="form-control o_survey_question_text_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_char_box if answer_lines else None"
t-att-data-question-type="question.question_type"
t-att-data-validation-length-min="question.validation_length_min if question.validation_required else False"
t-att-data-validation-length-max="question.validation_length_max if question.validation_required else False"/>
</div>
</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"/>
</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">
<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>
</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">
<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>
</div>
</template>
<template id="question_suggested_value_image" name="Image from the question suggested answer">
<t t-if="label.value_image">
<!-- 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)"/>
</div>
<div t-else="" t-field="label.value_image"
class="o_survey_choice_img d-flex my-3 justify-content-center"
t-options="{'widget': 'image', 'alt-field': 'name', 'itemprop': 'image'}"/>
</t>
</template>
<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"
t-att-data-name="question.id"
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"/>
<!--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'" />
<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 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-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>
</t>
<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 '')">
<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>
<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 ''"/>
<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 ''}">
<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>
</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>
</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"
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"/>
<!--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'" />
<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 '')">
<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>
<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>
</t>
<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 '')">
<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>
<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 ''"/>
<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 ''}">
<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>
</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>
</div>
</div>
</template>
<template id="question_matrix" name="Question: matrix">
<t t-set="comment_line" t-value="answer_lines.filtered(lambda line: line.value_char_box)"/>
<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">
<thead>
<tr>
<th> </th>
<th class="fw-normal" t-foreach="question.suggested_answer_ids" t-as="col_label"><span t-field="col_label.value" /></th>
</tr>
</thead>
<tbody>
<t t-set="item_idx" t-value="0"/>
<!-- For matrix, we have an extra check because we have rows * columns total options -->
<t t-set="useKeySelection" t-value="useKeySelection and (len(question.suggested_answer_ids) * len(question.matrix_row_ids)) &lt; len(letters)" />
<tr class="bg-white text-white" t-foreach="question.matrix_row_ids" t-as="row_label" t-att-id="row_label.id">
<th class="fw-normal text-start"><span t-field="row_label.value" /></th>
<t t-foreach="question.suggested_answer_ids" t-as="col_label">
<t t-set="answer" t-value="answer_lines.filtered(lambda line: line.suggested_answer_id == col_label and line.matrix_row_id == row_label)"/>
<td t-att-class="'o_survey_matrix_btn text-primary position-relative %s'
% ('o_survey_selected' if answer else '')">
<input t-att-type="'checkbox' if question.matrix_subtype == 'multiple' else 'radio'"
t-att-name="'%s_%s' % (question.id, row_label.id)" t-att-value='col_label.id'
t-att-checked="'checked' if answer else None"
t-att-data-row-id="row_label.id"
t-att-data-selection-key="letters[item_idx] if useKeySelection else ''"
class="o_survey_form_choice_item d-none"/>
<i t-att-class="'o_survey_matrix_empty_checkbox fa fa-%s position-relative'
% ('square-o' if question.matrix_subtype == 'multiple' else 'circle-thin')"></i>
<i t-att-class="'fa fa-%s position-relative'
% ('check-square' if question.matrix_subtype == 'multiple' else 'check-circle')"></i>
<t t-call="survey.survey_selection_key">
<t t-set="selection_key_class"
t-value="'position-absolute float-end fw-bold %s' % ('o_survey_radio_btn' if question.matrix_subtype != 'multiple' else '')"/>
</t>
<t t-set="item_idx" t-value="item_idx + 1"/>
</td>
</t>
</tr>
</tbody>
</table>
<div t-if='question.comments_allowed'>
<textarea type="text" class="form-control o_survey_question_text_box o_survey_comment bg-transparent rounded-0 p-0 mt-3"
t-att-placeholder="question.comments_message or default_comments_message if not survey_form_readonly else ''"
t-att-name="'%s_%s' % (question.id, 'comment')"><t t-esc="comment_line.value_char_box if comment_line else ''"/></textarea>
</div>
</template>
<template id="survey_selection_key">
<div t-if="useKeySelection" t-att-class="'o_survey_choice_key bg-white rounded %s' % selection_key_class">
<span class="o_survey_key text-center position-absolute bg-white rounded-start py-0 ps-2"><span class="text-primary text-center text-center w-100 position-relative">Key</span></span>
<span class="text-primary text-center w-100 position-relative" t-esc="letters[item_idx]"/>
</div>
</template>
<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>
<div class="o_survey_progress progress flex-grow-1">
<div class="progress-bar bg-primary" t-att-style="'width: ' + str(percentage) + '%'"/>
</div>
</t>
</template>
</data>
</odoo>

View file

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo><data>
<!-- ============================================================ -->
<!-- Errors / Corner case management -->
<!-- ============================================================ -->
<!-- Forbidden error messages-->
<template id="survey_403_page" name="Survey: custom 403 page">
<t t-call="survey.layout">
<div id="wrap">
<div class="container">
<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> ?
</p>
</div>
</div>
</t>
</template>
<!-- Error: void survey -->
<template id="survey_void_content" name="Survey: void content">
<t t-call="survey.layout">
<t t-if="answer.test_entry" t-call="survey.survey_button_form_view" />
<div class="wrap">
<div class="container">
<div class="jumbotron mt32">
<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"
class="btn btn-secondary"
groups="survey.group_survey_manager">Edit in backend</a>
</p>
<p t-else="">
No question yet, come back later.
</p>
</div>
</div>
</div>
</t>
</template>
<!-- Error: auth required -->
<template id="survey_auth_required" name="Survey: login required">
<t t-call="survey.layout">
<div class="wrap">
<div class="container">
<div class="jumbotron mt32">
<h1>Login required</h1>
<p>This survey is open only to registered people. Please
<a t-att-href="redirect_url">log in</a>.
</p>
</div>
</div>
</div>
</t>
</template>
<!-- Expired (closed) survey page -->
<template id="survey_closed_expired" name="Survey: expired">
<t t-call="survey.layout">
<div class="wrap">
<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>
</div>
</div>
</div>
</t>
</template>
<!-- ============================================================ -->
<!-- Tools / Utilities -->
<!-- ============================================================ -->
<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>
</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>
</t>
</div>
</template>
<!-- Survey Home page - Session Code
Used in 'session mode' to give an easy access to the survey through the '/s' route. -->
<template id="survey_session_code" name="Survey: Access Code page">
<t t-call="survey.layout">
<div class="wrap o_survey_wrap pb16 d-flex">
<div class="container o_survey_quick_access d-flex flex-column">
<div class="d-flex flex-grow-1 align-items-center">
<div class="w-100 px-4 px-md-0">
<div class="text-center mb32">
<h3>Enter Session Code</h3>
</div>
<div class="row">
<div class="col-12 col-md-4 offset-md-4 text-center">
<input id="session_code"
type="text" placeholder="e.g. 4812"
autocomplete="off"
t-attf-value="{{session_code if session_code else ''}}"
class="form-control o_survey_question_text_box fw-bold bg-transparent text-primary text-center rounded-0 p-2 w-100"/>
</div>
<div class="col-12 col-md-4 offset-md-4 text-center o_survey_error text-danger h4 pt-2 px-0" role="alert">
<span t-attf-class="o_survey_session_error_invalid_code {{'d-none' if error != 'survey_wrong' else ''}}">Oops! No survey matches this code.</span>
<span t-attf-class="o_survey_session_error_not_launched {{'d-none' if error != 'survey_session_not_launched' else ''}}">The session did not start yet.</span>
</div>
</div>
<div class="text-center mt32 p-2">
<button groups="survey.group_survey_user" type="button" t-attf-class="o_survey_launch_session btn btn-primary {{'d-none' if error != 'survey_session_not_launched' else ''}}" t-att-data-survey-id="survey_id">Launch Session</button>
<button type="submit" t-attf-class="btn btn-primary {{'d-none' if error == 'survey_session_not_launched' and request.env.user.has_group('survey.group_survey_user') else ''}}">Join Session</button>
</div>
</div>
</div>
</div>
</div>
</t>
</template>
<template id="survey_navigation" name="Survey: Navigation">
<div class="d-inline-block">
<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" />
</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" />
</button>
</div>
</template>
</data>
</odoo>

View file

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Survey: printable page view (all pages) -->
<template id="survey_page_print" name="Survey: print page">
<t t-call="survey.layout">
<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'>
<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>
<div role="form">
<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]" />
<div class="o_page_header mb-5">
<h1 t-field='question.title' class="text-break" />
<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>
<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>
</h2>
<div class="text-muted oe_no_empty mt-1 text-break" t-if="not is_html_empty(question.description)" t-field='question.description'/>
<t t-if="question.question_type in ['numerical_box', 'date', 'datetime', 'text_box', 'char_box']">
<t t-if="answer_lines">
<t t-set="answer_line" t-value="answer_lines[0]"/>
<t t-if="answer_line.skipped">
<!-- question was skipped, display an orange block with the text "Skipped" in place of the answer -->
<div class="row g-0">
<div class="col-12 col-md-6 col-lg-4 rounded ps-4 o_survey_question_skipped">
<input type="text"
t-attf-class="form-control fst-italic o_survey_question_{{question.question_type}} bg-transparent rounded-0 p-0" value="Skipped"/>
</div>
</div>
</t>
<t t-elif="answer_line.survey_id.scoring_type != 'no_scoring' and question.question_type in ['numerical_box', 'date', 'datetime'] and question['answer_%s' % question.question_type]">
<div class="row g-0">
<div t-attf-class="col-12 col-md-6 col-lg-4 rounded ps-4 #{'bg-success' if answer_line.answer_is_correct else 'bg-danger'}">
<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"/>
</div>
</div>
</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 == '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 t-if="answer_lines.survey_id.scoring_type != 'no_scoring'
and question.question_type in ['numerical_box', 'date', 'datetime']
and question['answer_%s' % question.question_type]
and not answer_line.answer_is_correct">
<div class="row g-0">
<t t-set="correct_answer" t-value="question['answer_%s' % question.question_type ]"/>
<div class="col-12 text-success mt-1">
The correct answer was:
<strong t-esc="correct_answer" t-if="question.question_type == 'numerical_box'"/>
<strong t-esc="format_date(correct_answer)" t-if="question.question_type == 'date'"/>
<strong t-esc="format_datetime(correct_answer)" t-if="question.question_type == 'datetime'"/>
</div>
</div>
</t>
</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 == '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>
<t t-if="question.question_type == 'simple_choice'" t-call="survey.question_simple_choice"/>
<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="answer_lines">
<t t-if="answer_lines[0].skipped">
<div class="row g-0">
<div class="col-12 o_survey_choice_question_skipped mt-1">
This question was skipped
</div>
</div>
</t>
</t>
</t>
<div class="o_survey_question_error overflow-hidden border-0 py-0 px-3 alert alert-danger" role="alert"></div>
</div>
</t>
</t>
<!--Set question to false to avoid background miss match as last question is still in context and is used in survey.layout t-call.-->
<t t-set="question" t-value="False"/>
</fieldset>
</div>
</div>
</div>
</t>
</template>
<!-- simple template with no assets, to show title on the certification preview -->
<template id="certification_preview">
<html>
<head>
<title t-esc="'%s Preview' % page_title"/>
<link rel="shortcut icon" href="/web/static/img/favicon.ico" type="image/x-icon"/>
</head>
<body style="margin:0;">
<iframe type="application/pdf" t-att-src="preview_url" frameBorder="0" width="100%" height="100%"/>
</body>
</html>
</template>
</data>
</odoo>

View file

@ -0,0 +1,513 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="survey_page_statistics" name="Survey: result statistics page">
<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">
<t t-call="survey.survey_page_statistics_header" />
<t t-call="survey.survey_page_statistics_inner" />
</div>
</t>
</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>
</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">
<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/>
</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>
</div>
</template>
<template id="survey_page_statistics_question" name="Question: result statistics">
<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']"/>
<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
</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>
</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">
<div t-if="question_and_page_data" class="justify-content-between w-100">
<ul class="nav o_survey_results_topbar_dropdown_filters">
<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"
t-attf-class="btn btn-outline-primary dropdown-toggle #{'active' if search_finished else ''}">
<span t-if="search_finished">Completed surveys</span>
<span t-else="">All surveys</span>
</a>
<div class="dropdown-menu">
<a t-attf-class="#{dropdown_item_classes} filter-finished-or-not #{'active' if not search_finished else ''}">
<span>All surveys</span>
<span t-if="not search_finished" t-esc="survey_data['count_all']" class="badge rounded-pill text-bg-primary ms-3"/>
</a>
<a t-attf-class="#{dropdown_item_classes} filter-finished #{'active' if search_finished else ''}">
<span>Completed surveys</span>
<span t-if="not search_finished" t-esc="survey_data['count_finished']" class="badge rounded-pill text-bg-primary ms-3"/>
</a>
</div>
</li>
<li t-if="survey.scoring_type != 'no_scoring'" class="nav-item dropdown me-2 my-1">
<a href="#" role="button" data-bs-toggle="dropdown"
t-attf-class="btn btn-outline-primary dropdown-toggle #{'active' if search_passed_or_failed else ''}">
<span t-if="search_failed">Failed only</span>
<span t-elif="search_passed">Passed only</span>
<span t-else="">Passed and Failed</span>
</a>
<div class="dropdown-menu">
<a t-attf-class="#{dropdown_item_classes} filter-passed-and-failed #{'active' if not search_passed_or_failed else ''}">
<span>Passed and Failed</span>
<span t-if="not search_passed_or_failed" t-esc="survey_data['count_all']" class="badge rounded-pill text-bg-primary ms-3"/>
</a>
<a t-attf-class="#{dropdown_item_classes} filter-passed #{'active' if search_passed else ''}">
<span>Passed only</span>
<span t-if="not search_passed_or_failed" t-esc="survey_data['count_passed']" class="badge rounded-pill text-bg-primary ms-3"/>
</a>
<a t-attf-class="#{dropdown_item_classes} filter-failed #{'active' if search_failed else ''}">
<span>Failed only</span>
<span t-if="not search_passed_or_failed" t-esc="survey_data['count_failed']" class="badge rounded-pill text-bg-primary ms-3"/>
</a>
</div>
</li>
</ul>
<ul class="nav o_survey_results_topbar_answer_filters mt-2">
<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>
<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>
</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>
</div>
</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"/>
</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>Occurrence</th>
<th t-if="question.is_scored_question">Score</th>
</tr>
</thead>
<tbody>
<tr t-foreach="question_data['common_lines']" t-as="common_line">
<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>
<i t-if="right_answer" class="fa fa-check"/>
</t>
<t t-elif="question.question_type == 'date'">
<t t-set="right_answer" t-value="common_line[0] == question.answer_date"/>
<span t-esc="common_line[0]" t-options='{"widget": "date"}'/>
<i t-if="right_answer" class="fa fa-check"/>
</t>
<t t-elif="question.question_type == 'datetime'">
<t t-set="right_answer" t-value="common_line[0] == question.answer_datetime"/>
<span t-esc="common_line[0]" t-options='{"widget": "datetime"}'/>
<i t-if="right_answer" class="fa fa-check"/>
</t>
</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>
<span t-else="">0</span>
</td>
</tr>
</tbody>
</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"/>
</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>
<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'))">
<!-- canvas element for drawing bar chart -->
<canvas/>
</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">
<thead>
<tr>
<th>Answer</th>
<th>User Choice</th>
<th t-if="question.is_scored_question">Score</th>
</tr>
</thead>
<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']"/>
</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">
<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"
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>
</tr>
</tbody>
</table>
</div>
</div>
<div t-if="comment_lines" t-call="survey.question_result_comments" />
</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"
t-att-data-question-id= "question.id"
data-graph-type= "multi_bar"
t-att-data-graph-data="graph_data">
<!-- canvas element for drawing Multibar chart -->
<canvas/>
</div>
<div role="tabpanel" t-attf-class="tab-pane #{'active' if not question_answered else ''}" t-att-id="'survey_data_question_%d' % question.id">
<table class="table table-hover table-sm text-end">
<thead t-if="table_data">
<tr>
<th></th>
<th class="text-end" t-foreach="table_data[0]['columns']" t-as="column_data">
<span t-esc="column_data['suggested_answer'].value"></span>
</th>
</tr>
</thead>
<tbody>
<tr t-foreach="table_data" t-as="choice_data">
<td>
<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"/>
</td>
</tr>
</tbody>
</table>
</div>
<div t-if="comment_lines" t-call="survey.question_result_comments" />
</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">
<thead>
<tr>
<th>#</th>
<th>Comment</th>
</tr>
</thead>
<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>
</td>
<td>
<span t-field="input_line.value_char_box"></span><br/>
</td>
</tr>
</tbody>
</table>
</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>
</template>
<template id="survey_remove_unnecessary_decimals" name="Survey: remove .0">
<t t-esc="value_to_format if value_to_format % 1 else int(value_to_format)"/>
</template>
</data>
</odoo>

View file

@ -0,0 +1,209 @@
<?xml version="1.0" encoding="utf-8"?>
<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">
<!--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>
<xpath expr="//div[@id='wrapwrap']" position="attributes">
<attribute name="t-att-style"
add="(('background-image: url(' + survey.session_question_id.background_image_url + ');')
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 '')"/>
<attribute name="t-att-class" add="'o_survey_background'"/>
</xpath>
<xpath expr="//head/t[@t-call-assets][last()]" position="after">
<t t-call-assets="survey.survey_assets" lazy_load="True"/>
<t t-call-assets="survey.survey_user_input_session_assets" lazy_load="True"/>
</xpath>
<xpath expr="//header" position="before">
<t t-set="no_header" t-value="True"/>
<t t-set="no_footer" t-value="True"/>
</xpath>
<xpath expr="//header" position="after">
<div id="wrap" class="oe_structure oe_empty"/>
</xpath>
</template>
<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"
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>
<a role="button"
class="fw-bold fa fa-chevron-right o_survey_session_navigation o_survey_session_navigation_next p-3" />
</div>
</div>
</t>
</template>
<template id="user_input_session_manage" name="Survey: Manage Session">
<t t-call="survey.user_input_session">
<t t-call="survey.user_input_session_manage_content" />
</t>
</template>
<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_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-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()"
t-att-data-time-limit-minutes="question.time_limit / 60"
t-att-data-is-scored-question="is_scored_question"
t-att-data-session-show-leaderboard="survey.session_show_leaderboard"
t-att-data-question-statistics="question_statistics_graph"
t-att-data-question-type="question.question_type"
t-att-data-has-correct-answers="any(answer.is_correct for answer in question.suggested_answer_ids)"
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-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"
t-att-data-refresh-background="any(page.background_image for page in survey.page_ids)"
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" />
</h3>
<h1 t-if="question.is_time_limited" class="o_survey_timer_container">
<span class="o_survey_timer d-inline-block"/>
</h1>
<div class="text-end d-flex flex-column justify-content-center">
<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">
<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 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" />
<a role="button"
class="fw-bold fa fa-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>
</div>
<div t-attf-class="d-flex flex-column flex-grow-1 #{'justify-content-center' if not show_text_answers else ''} #{'align-items-center' if show_bar_chart else ''}">
<!-- Has to stay in 'style' attribute for Chartjs -->
<div t-if="show_bar_chart" class="p-2 o_survey_session_chart"
style="position: relative; width: 75vw; height: 70vh;">
<!-- canvas element for drawing bar chart -->
<canvas />
</div>
<div t-elif="show_text_answers" class="p-2 pt-4 o_survey_session_text_answers_container">
</div>
<div t-elif="question.is_page and not is_html_empty(question.description)" class="mb-6 o_survey_manage_fontsize_14" t-field="question.description" />
<div t-else="" class="mb-6">
<h2 class="fw-normal mb-3">
<span>Waiting for attendees...</span>
<span>
<span class="o_survey_session_answer_count">0</span>
/
<span t-esc="survey.session_answer_count" />
</span>
</h2>
<div class="progress">
<div class="progress-bar fw-bold" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></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>
</div>
</div>
</div>
<div class="o_survey_session_leaderboard w-100 flex-column flex-grow-1" style="display: none;">
<!--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">
<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>
</div>
<div class="justify-content-center d-flex flex-column flex-grow-1 mt-5 mb-5 pb-5 o_survey_session_leaderboard_container"/>
</div>
</div>
</div>
</template>
<template id="user_input_session_leaderboard" name="Survey User Input Leaderboard">
<div t-if="leaderboard" class="position-relative mb-5" t-attf-style="height: calc(3.8rem * #{len(leaderboard)});">
<t t-set="max_score" t-value="max(score.get('scoring_total', 1) for score in leaderboard) or 1" />
<t t-set="max_updated_score" t-value="max(score.get('updated_score', 1) for score in leaderboard)" />
<t t-foreach="leaderboard" t-as="score">
<div class="o_survey_session_leaderboard_item ms-2 d-flex position-absolute"
t-attf-style="top: calc(#{score_index} * 3.8rem);"
t-att-data-current-position="str(score_index)"
t-att-data-new-position="str(score.get('leaderboard_position', score_index))"
t-att-data-question-score="str(round(score.get('question_score', 0)))"
t-att-data-current-score="str(round(score.get('scoring_total', 0)))"
t-att-data-updated-score="str(round(score.get('updated_score', 0)))"
t-att-data-max-question-score="round(score.get('max_question_score', 1))"
t-att-data-max-updated-score="round(max_updated_score)">
<div class="d-inline-block fw-bold align-top">
<div class="d-inline-block me-2 o_survey_session_leaderboard_score" t-esc="'%.0f p' % score['scoring_total']" />
</div>
<!-- We keep "18rem" of space to display the points / nickname.
Then, the length of the bar is a percentage of the attendee's score compared to the max_score. -->
<t t-set="width_ratio" t-value="round(round(score['scoring_total'], 3) / round(max_score, 3), 3)"/>
<t t-set="width_ratio_question" t-value="str(round(round(score.get('question_score', 0), 3) / round(score.get('max_question_score', 1), 3), 3))"/>
<div class="o_survey_session_leaderboard_bar ms-2 align-top d-inline-block text-end fw-bold"
t-att-style="'width: calc(calc(%s - 18rem) * %s)' % ('100%', width_ratio)"
t-att-data-width-ratio="width_ratio">
</div>
<div class="o_survey_session_leaderboard_bar_question me-2 align-top d-inline-block text-end fw-bold position-relative"
style="width: 0px;"
t-att-data-width-ratio="width_ratio_question"
t-att-data-max-question-score="str(score.get('max_question_score', 1))"
t-att-data-question-score="str(score.get('question_score', 0))">
<div class="o_survey_session_leaderboard_bar_question_score position-absolute"></div>
</div>
<div class="o_survey_session_leaderboard_name d-inline-block">
<span t-if="score.get('nickname')" t-esc="score['nickname']" />
<span t-else="">Anonymous</span>
</div>
</div>
</t>
</div>
</template>
</data>
</odoo>

View file

@ -0,0 +1,265 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- USER INPUTS -->
<record id="survey_user_input_view_search" model="ir.ui.view">
<field name="name">survey.user_input.view.search</field>
<field name="model">survey.user_input</field>
<field name="arch" type="xml">
<search string="Search Survey User Inputs">
<field name="email" string="Participant" filter_domain="[
'|',
('partner_id', 'ilike', self),
('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')]"/>
<separator/>
<filter string="Quizz 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">
<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'}"/>
</group>
</search>
</field>
</record>
<record id="survey_user_input_view_form" model="ir.ui.view">
<field name="name">survey.user_input.view.form</field>
<field name="model">survey.user_input</field>
<field name="arch" type="xml">
<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"/>
<field name="state" widget="statusbar"/>
</header>
<sheet>
<field name="attempts_count" invisible="1"/>
<div class="oe_button_box" name="button_box">
<button name="action_redirect_to_attempts"
type="object"
class="oe_stat_button"
attrs="{'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="Passed"
attrs="{'invisible': ['|', '|', ('test_entry', '=', True), ('scoring_type', '=', 'no_scoring'), ('scoring_success', '=', False)]}"/>
<group col="2">
<group>
<field name="survey_id"/>
<field name="create_date"/>
<field name="deadline" attrs="{'invisible': [('state', '=', 'done'), ('deadline', '=', False)]}"/>
<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">
<field name="attempts_number" nolabel="1"/>
/
<field name="attempts_limit" nolabel="1"/>
</div>
<field name="test_entry" groups="base.group_no_one"/>
</group>
<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">
<field name="scoring_percentage" nolabel="1"/>
<span>%</span>
</div>
<field name="partner_id"/>
<field name="email" widget="email"/>
<field name="access_token" groups="base.group_no_one"/>
</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"/>
<field name="create_date" optional="hidden"/>
<field name="page_id" optional="hidden"/>
<field name="question_id"/>
<field name="answer_type" optional="hidden"/>
<field name="skipped" hide="1"/>
<field name="display_name" string="Answer"/>
<field name="answer_is_correct"/>
<field name="answer_score" sum="Score"/>
</tree>
</field>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="activity_ids"/>
<field name="message_ids"/>
</div>
</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="model">survey.user_input</field>
<field name="arch" type="xml">
<tree string="Survey User inputs" decoration-muted="test_entry == True" create="false">
<field name="create_date"/>
<field name="survey_id"/>
<field name="nickname" optional="hide"/>
<field name="partner_id" optional="show"/>
<field name="email" optional="show"/>
<field name="attempts_number"/>
<field name="deadline"/>
<field name="test_entry" 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>
</field>
</record>
<record id="survey_user_input_viuew_kanban" model="ir.ui.view">
<field name="name">survey.user_input.view.kanban</field>
<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>
</templates>
</kanban>
</field>
</record>
<record model="ir.actions.act_window" id="action_survey_user_input">
<field name="name">Participations</field>
<field name="res_model">survey.user_input</field>
<field name="view_mode">tree,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>
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">
No answers yet!
</p><p>
You can share your links through different means: email, invite shortcut, live presentation, ...
</p>
</field>
</record>
<!-- USER INPUT LINES
.. note:: these views are useful mainly for technical users/administrators -->
<record id="survey_user_input_line_view_form" model="ir.ui.view">
<field name="name">survey.user_input.line.view.form</field>
<field name="model">survey.user_input.line</field>
<field name="arch" type="xml">
<form string="User input line details" create="false">
<sheet>
<group col="4">
<field name="question_id"/>
<field name="create_date"/>
<field name="answer_type"/>
<field name="skipped" />
<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="matrix_row_id" colspan='2' />
<field name="suggested_answer_id" colspan='2' attrs="{'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="model">survey.user_input.line</field>
<field name="arch" type="xml">
<tree string="Survey Answer Line" create="false">
<field name="survey_id"/>
<field name="user_input_id"/>
<field name="question_id"/>
<field name="create_date"/>
<field name="answer_type"/>
<field name="skipped"/>
<field name="answer_score" groups="base.group_no_one"/>
</tree>
</field>
</record>
<record id="survey_user_input_line_view_search" model="ir.ui.view">
<field name="name">survey.user_input.line.view.search</field>
<field name="model">survey.user_input.line</field>
<field name="arch" type="xml">
<search string="Search User input lines">
<field name="user_input_id"/>
<field name="survey_id"/>
<group expand="1" string="Group By">
<filter name="group_by_survey" string="Survey" domain="[]" context="{'group_by':'survey_id'}"/>
<filter name="group_by_user_input" string="User Input" domain="[]" context="{'group_by':'user_input_id'}"/>
</group>
</search>
</field>
</record>
<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="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">
<p class="o_view_nocontent_empty_folder">
No user input lines found
</p>
</field>
</record>
<menuitem name="Participations"
id="menu_survey_type_form1"
action="action_survey_user_input"
parent="menu_surveys"
sequence="1"/>
</data>
</odoo>