[IMP] {hr_recruitment_,website_slides_}survey: remove 'state' field

The goal of the draft state on survey is to have the survey under edition
mode before before sending it to participants. Under this mode:
  - the responsible can test it (can be done with "In Progress" mode)
  - the survey can't be answered (same as the state closed)

The risk that the survey can be leaked before being ready is really
limited. If it's a live survey, participants will have to guess the
4 digits access code and wait for the host to go to the next question.
Else, participant will have to guess the token.

Considering these facts, the use of the draft state is very limited so
'draft' state can be dropped. If we do so, we are left with only two
stages that are 'open' and 'closed'. But whether to consider survey
open or closed can be simply achieved with active field we already
have (if active=False, survey is closed, otherwise it's considered
as open).

So with this commit, we remove the state field from survey and thus
simplify the flow. It means that we no longer require 'Start Survey'
button, and so that button is also removed, and for the closed surveys,
instead of the button 'Set to draft', now we have a 'Reopen' button
which will activate the survey. And instead of displaying few buttons
after saving a record, we now display all the buttons from beginning.

Task ID-2389434
COM PR odoo/odoo#62712
ENT PR odoo/enterprise#15217
UPG PR odoo/upgrade#2006
This commit is contained in:
ijas ahammed
2021-02-10 17:03:03 +00:00
committed by Thibault Delavallée
parent ae7e1f64f8
commit 3010751e95
23 changed files with 20 additions and 69 deletions
@@ -2,7 +2,6 @@
<odoo><data noupdate="1">
<record id="survey_recruitment_form" model="survey.survey">
<field name="title">Recruitment Form</field>
<field name="state">open</field>
<field name="access_mode">token</field>
<field name="users_can_go_back" eval="True"/>
<field name="description" type="html">
+1 -1
View File
@@ -2,7 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'Surveys',
'version': '3.2',
'version': '3.3',
'category': 'Marketing/Surveys',
'description': """
Create beautiful surveys and visualize answers
+1 -1
View File
@@ -74,7 +74,7 @@ class Survey(http.Controller):
if survey_sudo.users_login_required and request.env.user._is_public():
return 'survey_auth'
if (survey_sudo.state == 'closed' or survey_sudo.state == 'draft' or not survey_sudo.active) and (not answer_sudo or not answer_sudo.test_entry):
if not survey_sudo.active and (not answer_sudo or not answer_sudo.test_entry):
return 'survey_closed'
if (not survey_sudo.page_ids and survey_sudo.questions_layout == 'page_per_section') or not survey_sudo.question_ids:
@@ -28,7 +28,6 @@ class UserInputSession(http.Controller):
We limit to sessions opened within the last 7 days to avoid potential abuses. """
if session_code:
matching_survey = request.env['survey.survey'].sudo().search([
('state', '=', 'open'),
('session_start_time', '>', fields.Datetime.now() - relativedelta(days=7)),
('session_code', '=', session_code),
], limit=1)
@@ -12,7 +12,6 @@
<record model="survey.survey" id="vendor_certification">
<field name="title">MyCompany Vendor Certification</field>
<field name="access_token">4ead4bc8-b8f2-4760-a682-1fde8ddb95ac</field>
<field name="state">open</field>
<field name="access_mode">public</field>
<field name="questions_layout">page_per_question</field>
<field name="users_can_go_back" eval="True" />
@@ -4,7 +4,6 @@
<record id="survey_demo_burger_quiz" model="survey.survey">
<field name="title">Burger Quiz</field>
<field name="access_token">burger00-quiz-1234-abcd-344ca2tgb31e</field>
<field name="state">open</field>
<field name="access_mode">public</field>
<field name="users_can_go_back" eval="True"/>
<field name="scoring_type">scoring_with_answers</field>
@@ -4,7 +4,6 @@
<record model="survey.survey" id="survey_feedback">
<field name="title">Feedback Form</field>
<field name="access_token">b135640d-14d4-4748-9ef6-344ca256531e</field>
<field name="state">open</field>
<field name="access_mode">public</field>
<field name="users_can_go_back" eval="True" />
<field name="questions_layout">page_per_section</field>
-1
View File
@@ -4,7 +4,6 @@
<record id="survey_demo_quiz" model="survey.survey">
<field name="title">Quiz about our Company</field>
<field name="access_token">b137640d-9876-1234-abcd-344ca256531e</field>
<field name="state">open</field>
<field name="access_mode">public</field>
<field name="users_can_go_back" eval="False"/>
<field name="scoring_type">scoring_with_answers</field>
+2 -21
View File
@@ -55,10 +55,6 @@ class Survey(models.Model):
help="This message will be displayed when survey is completed")
background_image = fields.Binary("Background Image")
active = fields.Boolean("Active", default=True)
state = fields.Selection(selection=[
('draft', 'Draft'), ('open', 'In Progress'), ('closed', 'Closed')
], string="Survey Stage", default='draft', required=True,
group_expand='_read_group_states')
# questions
question_and_page_ids = fields.One2many('survey.question', 'survey_id', string='Sections and Questions', copy=True)
page_ids = fields.One2many('survey.question', string='Pages', compute="_compute_page_and_question_ids")
@@ -292,10 +288,6 @@ class Survey(models.Model):
not survey.certification:
survey.certification_give_badge = False
def _read_group_states(self, values, domain, order):
selection = self.env['survey.survey'].fields_get(allfields=['state'])['state']['selection']
return [s[0] for s in selection]
# ------------------------------------------------------------
# CRUD
# ------------------------------------------------------------
@@ -400,9 +392,7 @@ class Survey(models.Model):
raise exceptions.UserError(_('Creating test token is not allowed for you.'))
else:
if not self.active:
raise exceptions.UserError(_('Creating token for archived surveys is not allowed.'))
elif self.state == 'closed':
raise exceptions.UserError(_('Creating token for closed surveys is not allowed.'))
raise exceptions.UserError(_('Creating token for closed/archived surveys is not allowed.'))
if self.access_mode == 'authentication':
# signup possible -> should have at least a partner to create an account
if self.users_can_signup and not user and not partner:
@@ -799,22 +789,13 @@ class Survey(models.Model):
# ACTIONS
# ------------------------------------------------------------
def action_draft(self):
self.write({'state': 'draft'})
def action_open(self):
self.write({'state': 'open'})
def action_close(self):
self.write({'state': 'closed'})
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 and self.questions_layout == 'page_per_section') or not self.question_ids:
raise exceptions.UserError(_('You cannot send an invitation for a survey that has no questions.'))
if self.state == 'closed':
if not self.active:
raise exceptions.UserError(_("You cannot send invitations for closed surveys."))
template = self.env.ref('survey.mail_template_user_input_invite', raise_if_not_found=False)
-1
View File
@@ -247,7 +247,6 @@ class TestSurveyCommon(SurveyCase):
'access_mode': 'public',
'users_login_required': True,
'users_can_go_back': False,
'state': 'open',
})
self.page_0 = self.env['survey.question'].with_user(self.survey_manager).create({
'title': 'First page',
@@ -17,7 +17,6 @@ class TestCertificationBadge(common.TestSurveyCommon):
'users_login_required': True,
'scoring_type': 'scoring_with_answers',
'certification': True,
'state': 'open',
})
self.certification_survey_2 = self.env['survey.survey'].with_user(self.survey_manager).create({
@@ -26,7 +25,6 @@ class TestCertificationBadge(common.TestSurveyCommon):
'users_login_required': True,
'scoring_type': 'scoring_with_answers',
'certification': True,
'state': 'open',
})
self.certification_badge = self.env['gamification.badge'].with_user(self.survey_manager).create({
@@ -160,7 +158,6 @@ class TestCertificationBadge(common.TestSurveyCommon):
'certification': True,
'certification_give_badge': True,
'certification_badge_id': self.certification_badge.id,
'state': 'open'
}
survey_1 = self.env['survey.survey'].create(vals.copy())
vals.update({'certification_badge_id': self.certification_badge_2.id})
@@ -28,7 +28,6 @@ class TestCertificationFlow(common.TestSurveyCommon, HttpCase):
'certification_mail_template_id': self.env.ref('survey.mail_template_certification').id,
'is_time_limited': True,
'time_limit': 10,
'state': 'open',
})
q01 = self._add_question(
@@ -135,7 +134,6 @@ class TestCertificationFlow(common.TestSurveyCommon, HttpCase):
'title': 'User randomized Certification',
'questions_layout': 'page_per_section',
'questions_selection': 'random',
'state': 'open',
'scoring_type': 'scoring_without_answers',
})
@@ -9,7 +9,6 @@ class TestSurveyComputePagesQuestions(common.TestSurveyCommon):
with self.with_user('survey_manager'):
survey = self.env['survey.survey'].create({
'title': 'Test compute survey',
'state': 'open',
})
page_0 = self.env['survey.question'].create({
-1
View File
@@ -26,7 +26,6 @@ class TestSurveyFlow(common.TestSurveyCommon, HttpCase):
'access_mode': 'public',
'users_login_required': False,
'questions_layout': 'page_per_section',
'state': 'open'
})
# First page is about customer data
+1 -1
View File
@@ -34,7 +34,7 @@ class TestSurveyInvite(common.TestSurveyCommon):
# closed
self.env['survey.survey'].with_user(self.survey_manager).create({
'title': 'S0',
'state': 'closed',
'active': False,
'question_and_page_ids': [
(0, 0, {'is_page': True, 'title': 'P0', 'sequence': 1}),
(0, 0, {'title': 'Q0', 'sequence': 2, 'question_type': 'text_box'})
+3 -6
View File
@@ -331,12 +331,9 @@ class TestSurveySecurityControllers(common.TestSurveyCommon, HttpCase):
def test_survey_start_short(self):
# avoid name clash with existing data
surveys = self.env['survey.survey'].search([
('state', '=', 'open'),
('session_state', 'in', ['ready', 'in_progress'])
])
surveys.write({'state': 'done'})
self.survey.write({
'state': 'open',
'session_state': 'ready',
'session_code': '123456',
'session_start_time': datetime.datetime.now(),
@@ -353,12 +350,12 @@ class TestSurveySecurityControllers(common.TestSurveyCommon, HttpCase):
response = self.url_open(f'/s/______')
self.assertFalse(self.survey.title in response.text)
# right short token, but wrong state
self.survey.state = 'draft'
# right short token, but closed survey
self.survey.action_archive()
response = self.url_open(f'/s/123456')
self.assertFalse(self.survey.title in response.text)
# right short token, but wrong `session_state`
self.survey.write({'state': 'open', 'session_state': False})
self.survey.write({'session_state': False, 'active': True})
response = self.url_open(f'/s/123456')
self.assertFalse(self.survey.title in response.text)
@@ -14,7 +14,6 @@ class TestUiCertification(HttpCaseWithUserDemo):
self.survey_certification = self.env['survey.survey'].create({
'title': 'MyCompany Vendor Certification',
'access_token': '4ead4bc8-b8f2-4760-a682-1fde8daaaaac',
'state': 'open',
'access_mode': 'public',
'users_can_go_back': True,
'users_login_required': True,
@@ -13,7 +13,6 @@ class TestUiFeedback(HttpCaseWithUserDemo):
self.survey_feedback = self.env['survey.survey'].create({
'title': 'User Feedback Form',
'access_token': 'b137640d-14d4-4748-9ef6-344caaaaaae',
'state': 'open',
'access_mode': 'public',
'users_can_go_back': True,
'questions_layout': 'page_per_section',
@@ -35,7 +35,6 @@ class TestUiSession(HttpCase):
survey_session = self.env['survey.survey'].create({
'title': 'User Session Survey',
'access_token': 'b137640d-14d4-4748-9ef6-344caaaaafe',
'state': 'open',
'access_mode': 'public',
'users_can_go_back': False,
'questions_layout': 'page_per_question',
+12 -19
View File
@@ -9,21 +9,19 @@
<field name="id" invisible="1"/>
<field name="session_state" invisible="1"/>
<header>
<button name="action_open" string="Start Survey" type="object" class="oe_highlight" attrs="{'invisible': ['|', ('state', '!=', 'draft'), ('id', '=', False)]}"/>
<button name="action_send_survey" string="Share" type="object" class="oe_highlight" states="open"/>
<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': ['|', ('state', '=', 'draft'), ('answer_done_count', '&lt;=', 0)]}"/>
attrs="{'invisible': [('answer_done_count', '&lt;=', 0)]}"/>
<button name="action_start_session" string="Create Live Session" type="object"
attrs="{'invisible': ['|', ('session_state', '!=', False), '|', ('state', '!=', 'open'), ('certification', '=', True)]}" />
attrs="{'invisible': ['|', ('session_state', '!=', False), '|', ('active', '=', False), ('certification', '=', True)]}" />
<button name="action_open_session_manager" string="Open Session Manager" type="object"
attrs="{'invisible': ['|', ('session_state', '=', False), ('state', '=', 'draft')]}" />
attrs="{'invisible': [('session_state', '=', False)]}" />
<button name="action_end_session" string="Close Live Session" type="object"
attrs="{'invisible': ['|', ('session_state', 'not in', ['ready', 'in_progress']), ('state', '=', 'draft')]}" />
<button name="action_draft" string="Set to draft" type="object" states="closed"/>
<button name="action_test_survey" string="Test" type="object" attrs="{'invisible': ['|', ('state', '=', 'closed'), ('id', '=', False)]}"/>
<button name="action_print_survey" string="Print" type="object" attrs="{'invisible': [('id', '=', False)]}"/>
<button name="action_close" string="Close" type="object" states="open"/>
<field name="state" widget="statusbar"/>
attrs="{'invisible': [('session_state', 'not in', ['ready', 'in_progress'])]}" />
<button name="action_test_survey" string="Test" type="object" attrs="{'invisible': [('active', '=', False)]}"/>
<button name="action_print_survey" string="Print" type="object"/>
<button name="action_archive" string="Close" type="object" attrs="{'invisible': [('active', '=', False)]}"/>
<button name="action_unarchive" string="Reopen" type="object" attrs="{'invisible': [('active', '=', True)]}"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
@@ -165,7 +163,6 @@
<field name="active" invisible="1"/>
<field name="certification" invisible="1"/>
<field name="title"/>
<field name="state" widget="badge" decoration-info="state == 'draft'" decoration-success="state == 'open'"/>
<field name="answer_count"/>
<field name="answer_done_count"/>
<field name="success_count"/>
@@ -181,7 +178,6 @@
<field name="model">survey.survey</field>
<field name="arch" type="xml">
<kanban sample="1">
<field name="state" />
<field name="title" />
<field name="answer_done_count" />
<field name="certification" />
@@ -192,6 +188,7 @@
<field name="activity_state" />
<field name="success_count"/>
<field name="success_ratio"/>
<field name='active'/>
<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_kanban_card_survey
@@ -203,7 +200,7 @@
</a>
<div class="dropdown-menu" role="menu">
<a role="menuitem" type="edit" class="dropdown-item">Edit Survey</a>
<a t-if="record.state.raw_value != 'closed'" role="menuitem" type="object" class="dropdown-item" name="action_send_survey">Share</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>
@@ -215,7 +212,7 @@
</div>
<div class="row">
<div class="col-10 p-0 pb-1">
<div class="container o_kanban_card_content" t-if="record.answer_done_count.raw_value != 0 or record.state.raw_value != 'draft'">
<div class="container o_kanban_card_content" t-if="record.answer_done_count.raw_value != 0">
<div class="row mt-4 ml-5">
<div class="col-4 p-0">
<a name="action_result_survey" type="object" class="d-flex flex-column align-items-center">
@@ -270,9 +267,6 @@
domain="[('activity_ids.date_deadline', '=', context_today().strftime('%Y-%m-%d'))]"/>
<filter invisible="1" string="Upcoming Activities" name="activities_upcoming_all"
domain="[('activity_ids.date_deadline', '&gt;', context_today().strftime('%Y-%m-%d'))]"/>
<group expand="0" string="Group By">
<filter string="State" name="groupby_state" context="{'group_by': 'state'}"/>
</group>
</search>
</field>
</record>
@@ -281,7 +275,6 @@
<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
@@ -54,7 +54,6 @@ class TestUi(TestUICommon):
furniture_survey = self.env['survey.survey'].create({
'title': 'Furniture Creation Certification',
'access_token': '5632a4d7-48cf-aaaa-8c52-2174d58cf50b',
'state': 'open',
'access_mode': 'public',
'users_can_go_back': True,
'users_login_required': True,
@@ -5,7 +5,6 @@
<record model="survey.survey" id="furniture_certification">
<field name="title">Furniture Creation Certification</field>
<field name="access_token">5632a4d7-48cf-4d25-8c52-2174d58cf50b</field>
<field name="state">open</field>
<field name="access_mode">public</field>
<field name="users_can_go_back" eval="True" />
<field name="users_login_required" eval="True" />
@@ -18,7 +18,6 @@ class TestCourseCertificationFailureFlow(TestSurveyCommon):
'is_attempts_limited': True,
'scoring_success_min': 100.0,
'attempts_limit': 2,
'state': 'open',
})
self._add_question(