[MERGE][IMP] survey: apply small tweaks on survey views (certification)
Purpose ====== This merge implies several small tweaks on the survey views, mainly to add support for the new certification fields. Show the quizz_passed field in the answers views ------------------------------------------------------------------- The quizz_passed field is now more important because it determines whether a certification has been successfully taken or not. The quizz_passed field is added in: - The search view of user_input - The list view of user_input - The form view of user_input (along with the score) Fix survey statistics computation ------------------------------------------- Fix the shared dict in the survey statistics computation that causes surveys to incorrectly share the same stats when computed in batch. Add a stat button on survey to show the certified count ------------------------------------------------------------------------ Add a stat button on the survey form view showing the amount of answers with the quizz_passed field set to True. It allows to quickly see people that have been granted the certification. On click, the stat button redirects to the answers list view with the "Quizz passed" filter defaulted to True. Task-1936539 closes odoo/odoo#31467 Signed-off-by: Jérome Maes (jem) <jem@openerp.com>
This commit is contained in:
@@ -9,11 +9,19 @@
|
||||
<div style="margin: 0px; padding: 0px; font-size: 13px;">
|
||||
<p style="margin: 0px; padding: 0px; font-size: 13px;">
|
||||
Dear ${object.partner_id.name or 'participant'}<br/><br/>
|
||||
We are conducting a survey and your response would be appreciated.
|
||||
% if object.survey_id.certificate:
|
||||
You have been invited to take a new certification.
|
||||
% else:
|
||||
We are conducting a survey and your response would be appreciated.
|
||||
% endif
|
||||
<div style="margin: 16px 0px 16px 0px;">
|
||||
<a href="${('%s?answer_token=%s' % (object.survey_id.public_url, object.token)) | safe}"
|
||||
style="background-color: #875A7B; padding: 8px 16px 8px 16px; text-decoration: none; color: #fff; border-radius: 5px; font-size:13px;">
|
||||
Start Survey
|
||||
% if object.survey_id.certificate:
|
||||
Start Certification
|
||||
% else:
|
||||
Start Survey
|
||||
% endif
|
||||
</a>
|
||||
</div>
|
||||
% if object.deadline:
|
||||
|
||||
@@ -70,6 +70,7 @@ class Survey(models.Model):
|
||||
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")
|
||||
|
||||
# scoring and certification fields
|
||||
scoring_type = fields.Selection([
|
||||
@@ -104,7 +105,7 @@ class Survey(models.Model):
|
||||
|
||||
@api.depends('user_input_ids.state', 'user_input_ids.test_entry')
|
||||
def _compute_survey_statistic(self):
|
||||
stat = dict.fromkeys(self.ids, {'invite_count': 0, 'answer_count': 0, 'answer_done_count': 0})
|
||||
stat = dict((cid, dict(invite_count=0, answer_count=0, answer_done_count=0)) for cid in self.ids)
|
||||
UserInput = self.env['survey.user_input']
|
||||
base_domain = ['&', ('survey_id', 'in', self.ids), ('test_entry', '!=', True)]
|
||||
|
||||
@@ -119,6 +120,22 @@ class Survey(models.Model):
|
||||
for survey in self:
|
||||
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']
|
||||
|
||||
for survey in self:
|
||||
survey.certified_count = stat.get(survey.id, 0)
|
||||
|
||||
def _compute_survey_url(self):
|
||||
""" Computes a public URL for the survey """
|
||||
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
@@ -434,7 +451,7 @@ class Survey(models.Model):
|
||||
def action_send_survey(self):
|
||||
""" Open a window to compose an email, pre-filled with the survey message """
|
||||
# Ensure that this survey has at least one page with at least one question.
|
||||
if not self.page_ids or not [page.question_ids for page in self.page_ids if page.question_ids]:
|
||||
if (not self.page_ids and self.questions_layout != 'page_per_question') or not self.question_ids:
|
||||
raise UserError(_('You cannot send an invitation for a survey that has no questions.'))
|
||||
|
||||
if self.stage_id.closed:
|
||||
@@ -503,6 +520,16 @@ class Survey(models.Model):
|
||||
action['context'] = ctx
|
||||
return action
|
||||
|
||||
@api.multi
|
||||
def action_survey_user_input_certified(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_quizz_passed': 1})
|
||||
action['context'] = ctx
|
||||
return action
|
||||
|
||||
@api.multi
|
||||
def action_survey_user_input_invite(self):
|
||||
action_rec = self.env.ref('survey.action_survey_user_input_notest')
|
||||
|
||||
@@ -32,6 +32,7 @@ class SurveyUserInput(models.Model):
|
||||
|
||||
# description
|
||||
survey_id = fields.Many2one('survey.survey', string='Survey', required=True, readonly=True, ondelete='cascade')
|
||||
scoring_type = fields.Selection(string="Scoring", related="survey_id.scoring_type")
|
||||
start_datetime = fields.Datetime('Start date and time', readonly=True)
|
||||
is_time_limit_reached = fields.Boolean("Is time limit reached?", compute='_compute_is_time_limit_reached')
|
||||
input_type = fields.Selection([
|
||||
@@ -58,7 +59,7 @@ class SurveyUserInput(models.Model):
|
||||
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 for the quiz (%)", compute="_compute_quizz_score", default=0.0)
|
||||
quizz_score = fields.Float("Score (%)", compute="_compute_quizz_score")
|
||||
# Stored for performance reasons while displaying results page
|
||||
quizz_passed = fields.Boolean('Quizz Passed', compute='_compute_quizz_passed', store=True, compute_sudo=True)
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ odoo.define('survey.tour_test_certification_failure', function (require) {
|
||||
var tour = require('web_tour.tour');
|
||||
|
||||
var failSteps = [{ // Page-1
|
||||
content: "Clicking on Start Survey",
|
||||
trigger: 'a.btn.btn-primary.btn-lg:contains("Start Survey")',
|
||||
content: "Clicking on Start Certification",
|
||||
trigger: 'a.btn.btn-primary.btn-lg:contains("Start Certification")',
|
||||
}, { // Question: Do we sell Acoustic Bloc Screens?
|
||||
content: "Selecting answer 'No'",
|
||||
trigger: 'div.js_question-wrapper:contains("Do we sell Acoustic Bloc Screens") select',
|
||||
|
||||
@@ -8,8 +8,8 @@ tour.register('test_certification_success', {
|
||||
url: '/survey/start/4ead4bc8-b8f2-4760-a682-1fde8ddb95ac'
|
||||
},
|
||||
[{ // Page-1
|
||||
content: "Clicking on Start Survey",
|
||||
trigger: 'a.btn.btn-primary.btn-lg:contains("Start Survey")',
|
||||
content: "Clicking on Start Certification",
|
||||
trigger: 'a.btn.btn-primary.btn-lg:contains("Start Certification")',
|
||||
}, { // Question: Do we sell Acoustic Bloc Screens?
|
||||
content: "Selecting answer 'Yes'",
|
||||
trigger: 'div.js_question-wrapper:contains("Do we sell Acoustic Bloc Screens") select',
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
icon="fa-envelope-o">
|
||||
<field string="Invitations" name="invite_count" widget="statinfo"/>
|
||||
</button>
|
||||
<button name="action_survey_user_input_certified"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
attrs="{'invisible': [('certificate', '=', False)]}"
|
||||
icon="fa-trophy">
|
||||
<field string="Certified" name="certified_count" widget="statinfo"/>
|
||||
</button>
|
||||
<button name="action_survey_user_input_completed"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
|
||||
@@ -178,7 +178,12 @@
|
||||
</p>
|
||||
</div>
|
||||
<a role="button" class="btn btn-primary btn-lg" t-att-href="'/survey/fill/%s/%s' % (survey.access_token, answer.token)">
|
||||
Start Survey
|
||||
<t t-if="survey.certificate">
|
||||
Start Certification
|
||||
</t>
|
||||
<t t-else="">
|
||||
Start Survey
|
||||
</t>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<separator/>
|
||||
<filter string="Invite" name="invite" domain="[('input_type', '=', 'link')]"/>
|
||||
<separator/>
|
||||
<filter string="Quizz passed" name="quizz_passed" domain="[('quizz_passed','=', True)]"/>
|
||||
<filter string="Test Entries" name="test" domain="[('test_entry','=', True)]"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter name="group_by_survey" string="Survey" domain="[]" context="{'group_by': 'survey_id'}"/>
|
||||
@@ -50,7 +51,9 @@
|
||||
<field name="partner_id"/>
|
||||
<field name="email" widget="email"/>
|
||||
<field name="test_entry" groups="base.group_no_one"/>
|
||||
<field name="quizz_score" groups="base.group_no_one"/>
|
||||
<field name="scoring_type" invisible="1"/>
|
||||
<field name="quizz_score" attrs="{'invisible': [('scoring_type', '=', 'no_scoring')]}"/>
|
||||
<field name="quizz_passed" attrs="{'invisible': [('scoring_type', '=', 'no_scoring')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="user_input_line_ids" mode="tree" attrs="{'readonly': False}">
|
||||
@@ -76,10 +79,11 @@
|
||||
<field name="deadline"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="email"/>
|
||||
<field name="input_type"/>
|
||||
<field name="input_type" groups="base.group_no_one"/>
|
||||
<field name="state"/>
|
||||
<field name="test_entry" invisible="True"/>
|
||||
<field name="quizz_score" groups="base.group_no_one"/>
|
||||
<field name="quizz_passed"/>
|
||||
<field name="quizz_score"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
Reference in New Issue
Block a user