[IMP] survey: ensure scored can be passed
Before this commit, it was possible to have users fill-in a scored survey with no way possible to pass it because no answer had any positive score obtainable. We keep here the check on sharing of the survey to avoid errors while configuring the survey, the same way it is already done when trying to share a survey without any question at all. Note that we are also adding this warning and the "This is a test survey" notice for survey_user and not only managers because users can also test their surveys... Task-3374592 closes odoo/odoo#130553 Signed-off-by: Stéphane Debauche (std) <std@odoo.com>
This commit is contained in:
@@ -121,8 +121,9 @@ class Survey(models.Model):
|
||||
('no_scoring', 'No scoring'),
|
||||
('scoring_with_answers', 'Scoring with answers at the end'),
|
||||
('scoring_without_answers', 'Scoring without answers at the end')],
|
||||
string="Scoring", required=True, store=True, readonly=False, compute="_compute_scoring_type", precompute=True)
|
||||
string='Scoring', required=True, store=True, readonly=False, compute='_compute_scoring_type', precompute=True)
|
||||
scoring_success_min = fields.Float('Required Score (%)', default=80.0)
|
||||
scoring_max_obtainable = fields.Float('Maximum obtainable score', compute='_compute_scoring_max_obtainable')
|
||||
# attendees context: attempts and time limitation
|
||||
is_attempts_limited = fields.Boolean('Limited number of attempts', help="Check this option if you want to limit the number of attempts per user",
|
||||
compute="_compute_is_attempts_limited", store=True, readonly=False)
|
||||
@@ -196,6 +197,19 @@ class Survey(models.Model):
|
||||
for survey in self.filtered(lambda survey: survey.background_image and survey.access_token):
|
||||
survey.background_image_url = "/survey/%s/get_background_image" % survey.access_token
|
||||
|
||||
@api.depends(
|
||||
'question_and_page_ids',
|
||||
'question_and_page_ids.suggested_answer_ids',
|
||||
'question_and_page_ids.suggested_answer_ids.answer_score',
|
||||
)
|
||||
def _compute_scoring_max_obtainable(self):
|
||||
for survey in self:
|
||||
survey.scoring_max_obtainable = sum(
|
||||
question.answer_score
|
||||
or sum(answer.answer_score for answer in question.suggested_answer_ids if answer.answer_score > 0)
|
||||
for question in survey.question_ids
|
||||
)
|
||||
|
||||
def _compute_users_can_signup(self):
|
||||
signup_allowed = self.env['res.users'].sudo()._get_signup_invitation_scope() == 'b2c'
|
||||
for survey in self:
|
||||
@@ -938,6 +952,11 @@ class Survey(models.Model):
|
||||
if not self.question_ids:
|
||||
raise UserError(_('You cannot send an invitation for a survey that has no questions.'))
|
||||
|
||||
# Ensure scored survey have a positive total score obtainable.
|
||||
if self.scoring_type != 'no_scoring' and self.scoring_max_obtainable <= 0:
|
||||
raise UserError(_("A scored survey needs at least one question that gives points.\n"
|
||||
"Please check answers and their scores."))
|
||||
|
||||
# Ensure that this survey has at least one section with question(s), if question layout is 'One page per section'.
|
||||
if self.questions_layout == 'page_per_section':
|
||||
if not self.page_ids:
|
||||
|
||||
@@ -5,7 +5,7 @@ from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from lxml import etree
|
||||
|
||||
from odoo import fields
|
||||
from odoo import fields, Command
|
||||
from odoo.addons.survey.tests import common
|
||||
from odoo.addons.mail.tests.common import MailCommon
|
||||
from odoo.exceptions import UserError
|
||||
@@ -37,26 +37,74 @@ class TestSurveyInvite(common.TestSurveyCommon, MailCommon):
|
||||
action = self.survey.action_send_survey()
|
||||
self.assertEqual(action['res_model'], 'survey.invite')
|
||||
|
||||
# Bad cases
|
||||
surveys = [
|
||||
# no page
|
||||
self.env['survey.survey'].create({'title': 'Test survey'}),
|
||||
# no questions
|
||||
self.env['survey.survey'].create({'title': 'Test survey', 'question_and_page_ids': [(0, 0, {'is_page': True, 'question_type': False, 'title': 'P0', 'sequence': 1})]}),
|
||||
# closed
|
||||
self.env['survey.survey'].with_user(self.survey_manager).create({
|
||||
'title': 'S0',
|
||||
bad_cases = [
|
||||
{}, # empty
|
||||
{ # no question
|
||||
'question_and_page_ids': [Command.create({'is_page': True, 'question_type': False, 'title': 'P0', 'sequence': 1})]
|
||||
}, {
|
||||
# scored without positive score obtainable
|
||||
'scoring_type': 'scoring_with_answers',
|
||||
'question_and_page_ids': [Command.create({'question_type': 'numerical_box', 'title': 'Q0', 'sequence': 1})],
|
||||
}, {
|
||||
# scored without positive score obtainable from simple choice
|
||||
'scoring_type': 'scoring_with_answers',
|
||||
'question_and_page_ids': [Command.create({
|
||||
'question_type': 'simple_choice',
|
||||
'title': 'Q0', 'sequence': 1,
|
||||
'suggested_answer_ids': [
|
||||
Command.create({'value': '1', 'answer_score': 0}),
|
||||
Command.create({'value': '2', 'answer_score': 0}),
|
||||
],
|
||||
})],
|
||||
}, {
|
||||
# closed
|
||||
'active': False,
|
||||
'question_and_page_ids': [
|
||||
(0, 0, {'is_page': True, 'question_type': False, 'title': 'P0', 'sequence': 1}),
|
||||
(0, 0, {'title': 'Q0', 'sequence': 2, 'question_type': 'text_box'})
|
||||
Command.create({'is_page': True, 'question_type': False, 'title': 'P0', 'sequence': 1}),
|
||||
Command.create({'title': 'Q0', 'sequence': 2, 'question_type': 'text_box'})
|
||||
]
|
||||
})
|
||||
},
|
||||
]
|
||||
for survey in surveys:
|
||||
good_cases = [
|
||||
{
|
||||
# scored with positive score obtainable
|
||||
'scoring_type': 'scoring_with_answers',
|
||||
'question_and_page_ids': [
|
||||
Command.create({'question_type': 'numerical_box', 'title': 'Q0', 'sequence': 1, 'answer_score': 1}),
|
||||
],
|
||||
}, {
|
||||
# scored with positive score obtainable from simple choice
|
||||
'scoring_type': 'scoring_with_answers',
|
||||
'question_and_page_ids': [
|
||||
Command.create({ # not sufficient
|
||||
'question_type': 'simple_choice',
|
||||
'title': 'Q0', 'sequence': 1,
|
||||
'suggested_answer_ids': [
|
||||
Command.create({'value': '1', 'answer_score': 0}),
|
||||
Command.create({'value': '2', 'answer_score': 0}),
|
||||
],
|
||||
}),
|
||||
Command.create({ # sufficient even if not 'is_correct'
|
||||
'question_type': 'simple_choice',
|
||||
'title': 'Q1', 'sequence': 2,
|
||||
'suggested_answer_ids': [
|
||||
Command.create({'value': '1', 'answer_score': 0}),
|
||||
Command.create({'value': '2', 'answer_score': 1}),
|
||||
],
|
||||
})],
|
||||
},
|
||||
]
|
||||
surveys = self.env['survey.survey'].with_user(self.survey_manager).create([
|
||||
{'title': 'Test survey', **case} for case in bad_cases + good_cases
|
||||
])
|
||||
|
||||
for survey in surveys[:len(bad_cases)]:
|
||||
with self.assertRaises(UserError):
|
||||
survey.action_send_survey()
|
||||
|
||||
for survey in surveys[len(bad_cases):]:
|
||||
survey.action_send_survey()
|
||||
|
||||
@users('survey_manager')
|
||||
def test_survey_invite(self):
|
||||
Answer = self.env['survey.user_input']
|
||||
@@ -95,7 +143,6 @@ class TestSurveyInvite(common.TestSurveyCommon, MailCommon):
|
||||
self.assertEqual(invite_form.existing_text,
|
||||
'The following customers have already received an invite: Caroline Customer.')
|
||||
|
||||
|
||||
@users('survey_manager')
|
||||
def test_survey_invite_authentication_nosignup(self):
|
||||
Answer = self.env['survey.user_input']
|
||||
@@ -121,7 +168,7 @@ class TestSurveyInvite(common.TestSurveyCommon, MailCommon):
|
||||
self.assertEqual(len(answers), 2)
|
||||
self.assertEqual(
|
||||
set(answers.mapped('email')),
|
||||
set([self.user_emp.email, self.user_portal.email]))
|
||||
{self.user_emp.email, self.user_portal.email})
|
||||
self.assertEqual(answers.mapped('partner_id'), self.user_emp.partner_id | self.user_portal.partner_id)
|
||||
|
||||
@users('survey_manager')
|
||||
|
||||
@@ -96,10 +96,12 @@
|
||||
<!-- ============================================================ -->
|
||||
|
||||
<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&model=survey.survey&id=#{survey.id}&action=survey.action_survey_form"><span t-if="answer and answer.test_entry">This is a Test Survey. </span><i class="oi oi-fw oi-arrow-right"/>Edit Survey</a>
|
||||
</div>
|
||||
<div groups="survey.group_survey_user" t-ignore="true" class="alert alert-info p-2 border-0 rounded-0 d-print-none css_editable_mode_hidden mb-0 text-center">
|
||||
<a t-attf-href="/web#view_type=form&model=survey.survey&id=#{survey.id}&action=survey.action_survey_form"><span>This is a Test Survey Entry. </span><i class="oi oi-fw oi-arrow-right"/>Edit Survey</a>
|
||||
</div>
|
||||
<div groups="survey.group_survey_user" t-if="survey.scoring_type != 'no_scoring' and survey.scoring_max_obtainable <= 0"
|
||||
t-ignore="true" class="alert alert-warning p-2 border-0 rounded-0 d-print-none css_editable_mode_hidden mb-0 text-center">
|
||||
<i class="fa fa-exclamation-triangle"/> It is currently not possible to pass this assessment because no question is configured to give any points.
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user