[REF] website_slide_survey: improve integration into eLeaning application
PURPOSE
eLearning should have its own application in manager. Indeed this is becoming
a big application and having it embedded inside Website application is not
enough anymore. It should also hold updated and easy-to-use menus,
navigation, actions and views in backend.
SPECIFICATIONS
Add menu entry inside Courses
* Certifications: kanban view of surveys of type certificate
Add menu entry inside Reporting
* Certifications: list view on surveys of type certificate
Columns: Title, Survey Stage, Registered People, Certified People, Attempts
Success Rate (certified/attempts), Average Results
LINKS
Task 1978729
PR #35061
Co-Authored-By: Thibault Delavallée <tde@odoo.com>
Co-Authored-By: Jérémy Hennecart <jeh@odoo.com>
This commit is contained in:
committed by
Thibault Delavallée
co-authored by
Thibault Delavallée
parent
ee10b19f67
commit
ee29641b08
@@ -71,11 +71,11 @@ class Survey(models.Model):
|
||||
users_can_signup = fields.Boolean('Users can signup', compute='_compute_users_can_signup')
|
||||
public_url = fields.Char("Public link", compute="_compute_survey_url")
|
||||
# statistics
|
||||
invite_count = fields.Integer("Invite", compute="_compute_survey_statistic")
|
||||
answer_count = fields.Integer("Started", compute="_compute_survey_statistic")
|
||||
answer_done_count = fields.Integer("Completed", compute="_compute_survey_statistic")
|
||||
certified_count = fields.Integer("Certified", compute="_compute_certified_count")
|
||||
|
||||
answer_count = fields.Integer("Registered", compute="_compute_survey_statistic")
|
||||
answer_done_count = fields.Integer("Attempts", compute="_compute_survey_statistic")
|
||||
answer_score_avg = fields.Float("Avg Score %", compute="_compute_survey_statistic")
|
||||
certified_count = fields.Integer("Certified", compute="_compute_survey_statistic")
|
||||
certified_ratio = fields.Integer("Certified Ratio", compute="_compute_certified_ratio")
|
||||
# scoring and certification fields
|
||||
scoring_type = fields.Selection([
|
||||
('no_scoring', 'No scoring'),
|
||||
@@ -121,38 +121,30 @@ class Survey(models.Model):
|
||||
for survey in self:
|
||||
survey.users_can_signup = signup_allowed
|
||||
|
||||
@api.depends('user_input_ids.state', 'user_input_ids.test_entry')
|
||||
@api.depends('user_input_ids.input_type', 'user_input_ids.state', 'user_input_ids.test_entry', 'user_input_ids.quizz_score', 'user_input_ids.quizz_passed')
|
||||
def _compute_survey_statistic(self):
|
||||
stat = dict((cid, dict(invite_count=0, answer_count=0, answer_done_count=0)) for cid in self.ids)
|
||||
stat = dict((cid, dict(answer_count=0, answer_done_count=0, certified_count=0, answer_score_avg_total=0.0)) for cid in self.ids)
|
||||
UserInput = self.env['survey.user_input']
|
||||
base_domain = ['&', ('survey_id', 'in', self.ids), ('test_entry', '!=', True)]
|
||||
|
||||
read_group_res = UserInput.read_group(base_domain, ['input_type', 'state'], ['survey_id', 'input_type', 'state'], lazy=False)
|
||||
read_group_res = UserInput.read_group(base_domain, ['survey_id', 'state'], ['survey_id', 'input_type', 'state', 'quizz_score', 'quizz_passed'], lazy=False)
|
||||
for item in read_group_res:
|
||||
stat[item['survey_id'][0]]['answer_count'] += item['__count']
|
||||
stat[item['survey_id'][0]]['answer_score_avg_total'] += item['quizz_score']
|
||||
if item['state'] == 'done':
|
||||
stat[item['survey_id'][0]]['answer_done_count'] += item['__count']
|
||||
if item['input_type'] == 'link':
|
||||
stat[item['survey_id'][0]]['invite_count'] += item['__count']
|
||||
if item['quizz_passed']:
|
||||
stat[item['survey_id'][0]]['certified_count'] += item['__count']
|
||||
|
||||
for survey in self:
|
||||
avg_total = stat[survey.id].pop('answer_score_avg_total')
|
||||
stat[survey.id]['answer_score_avg'] = avg_total / (stat[survey.id]['answer_done_count'] or 1)
|
||||
survey.update(stat[survey.id])
|
||||
|
||||
@api.depends('certificate', 'user_input_ids.quizz_passed', 'user_input_ids.test_entry')
|
||||
def _compute_certified_count(self):
|
||||
stat = dict((cid, 0) for cid in self.ids)
|
||||
certificate_surveys = self.filtered(lambda survey: survey.certificate)
|
||||
if certificate_surveys:
|
||||
read_group_res = self.env['survey.user_input'].read_group(
|
||||
[('survey_id', 'in', certificate_surveys.ids), ('test_entry', '!=', True), ('quizz_passed', '=', True)],
|
||||
[],
|
||||
['survey_id']
|
||||
)
|
||||
for item in read_group_res:
|
||||
stat[item['survey_id'][0]] += item['survey_id_count']
|
||||
|
||||
@api.depends('certified_count', 'answer_done_count')
|
||||
def _compute_certified_ratio(self):
|
||||
for survey in self:
|
||||
survey.certified_count = stat.get(survey.id, 0)
|
||||
survey.certified_ratio = survey.certified_count / (survey.answer_done_count or 1.0)
|
||||
|
||||
def _compute_survey_url(self):
|
||||
""" Computes a public URL for the survey """
|
||||
@@ -614,12 +606,11 @@ class Survey(models.Model):
|
||||
action['context'] = ctx
|
||||
return action
|
||||
|
||||
def action_survey_user_input_invite(self):
|
||||
def action_survey_user_input(self):
|
||||
action_rec = self.env.ref('survey.action_survey_user_input_notest')
|
||||
action = action_rec.read()[0]
|
||||
ctx = dict(self.env.context)
|
||||
ctx.update({'search_default_survey_id': self.ids[0],
|
||||
'search_default_invite': 1})
|
||||
ctx.update({'search_default_survey_id': self.ids[0]})
|
||||
action['context'] = ctx
|
||||
return action
|
||||
|
||||
|
||||
@@ -61,9 +61,8 @@ class SurveyUserInput(models.Model):
|
||||
# Pre-defined questions
|
||||
question_ids = fields.Many2many('survey.question', string='Predefined Questions', readonly=True)
|
||||
deadline = fields.Datetime('Deadline', help="Datetime until customer can open the survey and submit answers")
|
||||
|
||||
quizz_score = fields.Float("Score (%)", compute="_compute_quizz_score")
|
||||
# Stored for performance reasons while displaying results page
|
||||
quizz_score = fields.Float("Score (%)", compute="_compute_quizz_score", store=True, compute_sudo=True)
|
||||
quizz_passed = fields.Boolean('Quizz Passed', compute='_compute_quizz_passed', store=True, compute_sudo=True)
|
||||
|
||||
@api.depends('user_input_line_ids.answer_score', 'user_input_line_ids.question_id')
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
<sheet>
|
||||
<widget name="web_ribbon" text="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="action_survey_user_input_invite"
|
||||
<button name="action_survey_user_input"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
attrs="{'invisible': [('access_mode', '=', 'public')]}"
|
||||
icon="fa-envelope-o">
|
||||
<field string="Invitations" name="invite_count" widget="statinfo"/>
|
||||
<field string="Registered" name="answer_count" widget="statinfo"/>
|
||||
</button>
|
||||
<button name="action_survey_user_input_certified"
|
||||
type="object"
|
||||
@@ -132,9 +132,11 @@
|
||||
<field name="certificate" invisible="1"/>
|
||||
<field name="title"/>
|
||||
<field name="state"/>
|
||||
<field name="invite_count"/>
|
||||
<field name="answer_count"/>
|
||||
<field name="answer_done_count"/>
|
||||
<field name="certified_count"/>
|
||||
<field name="certified_ratio"/>
|
||||
<field name="answer_score_avg"/>
|
||||
<button name="certificate" icon="fa-trophy" title="Certificate" aria-label="Certificate" attrs="{'invisible': [('certificate', '=', False)]}"/>
|
||||
<!-- Tweak as icons aren't directly supported in xml -->
|
||||
</tree>
|
||||
@@ -144,7 +146,7 @@
|
||||
<field name="name">Kanban view for survey</field>
|
||||
<field name="model">survey.survey</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="state">
|
||||
<kanban>
|
||||
<field name="state" />
|
||||
<field name="title" />
|
||||
<field name="answer_done_count" />
|
||||
@@ -221,6 +223,7 @@
|
||||
]"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Category" name="groupby_category" context="{'group_by': 'category'}"/>
|
||||
<filter string="State" name="groupby_state" context="{'group_by': 'state'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
@@ -230,6 +233,7 @@
|
||||
<field name="name">Surveys</field>
|
||||
<field name="res_model">survey.survey</field>
|
||||
<field name="view_mode">kanban,tree,form,activity</field>
|
||||
<field name="context">{'search_default_groupby_state': 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Add a new survey
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
'views/assets.xml',
|
||||
'views/slide_channel_views.xml',
|
||||
'views/slide_slide_views.xml',
|
||||
'views/survey_survey_views.xml',
|
||||
'views/website_slides_menu_views.xml',
|
||||
'views/website_slides_templates_course.xml',
|
||||
'views/website_slides_templates_lesson.xml',
|
||||
'views/website_slides_templates_lesson_fullscreen.xml',
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<field name="model">slide.channel</field>
|
||||
<field name="inherit_id" ref="website_slides.slide_channel_view_kanban"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='members_running_count']" position="after">
|
||||
<xpath expr="//field[@name='website_published']" position="after">
|
||||
<field name="nbr_certification"/>
|
||||
</xpath>
|
||||
<xpath expr="//a[@name='action_redirect_to_done_members']/span" position="replace">
|
||||
|
||||
@@ -12,4 +12,18 @@
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="slide_slide_action_certification" model="ir.actions.act_window">
|
||||
<field name="name">Certifications</field>
|
||||
<field name="res_model">slide.slide</field>
|
||||
<field name="view_mode">tree,form,graph</field>
|
||||
<field name="domain">[('slide_type', '=', 'certification')]</field>
|
||||
<field name="context">{'default_slide_type': 'certification'}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Add a new certification
|
||||
</p>
|
||||
</field>
|
||||
<field name="view_id" ref="website_slides.view_slide_slide_tree"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="survey_survey_action_slides" model="ir.actions.act_window">
|
||||
<field name="name">Certifications</field>
|
||||
<field name="res_model">survey.survey</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="domain">[('certificate', '=', True)]</field>
|
||||
<field name="context">{'default_certificate': True}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Add a new certification
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="survey_survey_action_slides_report" model="ir.actions.act_window">
|
||||
<field name="name">Certifications</field>
|
||||
<field name="res_model">survey.survey</field>
|
||||
<field name="view_mode">tree,kanban,form,graph</field>
|
||||
<field name="domain">[('certificate', '=', True)]</field>
|
||||
<field name="context">{'default_certificate': True}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Add a new certification
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<menuitem name="Certifications"
|
||||
id="website_slides_menu_courses_certification"
|
||||
parent="website_slides.website_slides_menu_courses"
|
||||
sequence="3"
|
||||
action="survey_survey_action_slides"/>
|
||||
|
||||
<menuitem name="Certifications"
|
||||
id="website_slides_menu_report_certification"
|
||||
parent="website_slides.website_slides_menu_report"
|
||||
sequence="40"
|
||||
action="survey_survey_action_slides_report"/>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user