diff --git a/addons/survey/__manifest__.py b/addons/survey/__manifest__.py index abadb891fd5..e78a4008f95 100644 --- a/addons/survey/__manifest__.py +++ b/addons/survey/__manifest__.py @@ -99,6 +99,9 @@ sent mails with personal token for the invitation of the survey. 'web.assets_tests': [ 'survey/static/tests/**/*', ], + 'web.assets_common': [ + 'survey/static/src/js/tours/survey_tour.js', + ] }, 'license': 'LGPL-3', } diff --git a/addons/survey/models/survey_survey.py b/addons/survey/models/survey_survey.py index f9030b730d0..9c9189e6add 100644 --- a/addons/survey/models/survey_survey.py +++ b/addons/survey/models/survey_survey.py @@ -76,10 +76,10 @@ class Survey(models.Model): question_ids = fields.One2many('survey.question', string='Questions', compute="_compute_page_and_question_ids") question_count = fields.Integer('# Questions', compute="_compute_page_and_question_ids") questions_layout = fields.Selection([ - ('one_page', 'One page with all the questions'), + ('page_per_question', 'One page per question'), ('page_per_section', 'One page per section'), - ('page_per_question', 'One page per question')], - string="Pagination", required=True, default='one_page') + ('one_page', 'One page with all the questions')], + string="Pagination", required=True, default='page_per_question') questions_selection = fields.Selection([ ('all', 'All questions'), ('random', 'Randomized per Section')], @@ -200,7 +200,7 @@ class Survey(models.Model): } stat = dict((cid, dict(default_vals, 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)] + base_domain = [('survey_id', 'in', self.ids)] read_group_res = UserInput._read_group(base_domain, ['survey_id', 'state'], ['survey_id', 'state', 'scoring_percentage', 'scoring_success'], lazy=False) for item in read_group_res: @@ -953,7 +953,7 @@ class Survey(models.Model): return { 'type': 'ir.actions.act_url', 'name': "Test Survey", - 'target': 'new', + 'target': 'self', 'url': '/survey/test/%s' % self.access_token, } @@ -961,8 +961,7 @@ class Survey(models.Model): action = self.env['ir.actions.act_window']._for_xml_id('survey.action_survey_user_input') ctx = dict(self.env.context) ctx.update({'search_default_survey_id': self.ids[0], - 'search_default_completed': 1, - 'search_default_not_test': 1}) + 'search_default_completed': 1}) action['context'] = ctx return action @@ -970,16 +969,14 @@ class Survey(models.Model): action = self.env['ir.actions.act_window']._for_xml_id('survey.action_survey_user_input') ctx = dict(self.env.context) ctx.update({'search_default_survey_id': self.ids[0], - 'search_default_scoring_success': 1, - 'search_default_not_test': 1}) + 'search_default_scoring_success': 1}) action['context'] = ctx return action def action_survey_user_input(self): action = self.env['ir.actions.act_window']._for_xml_id('survey.action_survey_user_input') ctx = dict(self.env.context) - ctx.update({'search_default_survey_id': self.ids[0], - 'search_default_not_test': 1}) + ctx.update({'search_default_survey_id': self.ids[0]}) action['context'] = ctx return action diff --git a/addons/survey/models/survey_survey_template.py b/addons/survey/models/survey_survey_template.py index 82fde7ede6b..289257e108c 100644 --- a/addons/survey/models/survey_survey_template.py +++ b/addons/survey/models/survey_survey_template.py @@ -18,78 +18,67 @@ class SurveyTemplate(models.Model): @api.model def action_load_sample_feedback_form(self): + company = self.env.user.company_id.name return self.env['survey.survey'].create({ 'title': _('Feedback Form'), - 'description': _('What do you think of our new eShop? Let us hear your voice!'), - 'description_done': _('Thank you very much for your feedback. We at MyCompany value your opinion!'), + 'description': '
'.join([ + _('Please complete this very short survey to let us know how satisfied your are with our products.'), + _('Your responses will help us improve our product range to serve you even better.') + ]), + 'description_done': _('Thank you very much for your feedback. We at %s value your opinion very highly!', company), 'progression_mode': 'number', - 'questions_layout': 'one_page', + 'questions_layout': 'page_per_question', 'question_and_page_ids': [ (0, 0, { # survey.question - 'title': _('About you'), - 'is_page': True, - 'question_type': False - }), - (0, 0, { # survey.question - 'title': _('How frequently do you buy products online?'), + 'title': _('How frequently do you use our products?'), 'question_type': 'simple_choice', + 'constr_mandatory': True, 'suggested_answer_ids': [ (0, 0, { # survey.question.answer - 'value': _('Once a day') + 'value': _('Often (1-3 times per week)') }), (0, 0, { # survey.question.answer - 'value': _('Once a week') + 'value': _('Rarely (1-3 times per month)') }), (0, 0, { # survey.question.answer - 'value': _('Once a month') - }), - (0, 0, { # survey.question.answer - 'value': _('Once a year') - }), - (0, 0, { # survey.question.answer - 'value': _('Never') + 'value': _('Never (less than once a month)') }) ] }), (0, 0, { # survey.question - 'title': _('How many times did you order products on our website?'), - 'question_type': 'numerical_box' + 'title': _('How many orders did you pass during the last 6 months?'), + 'question_type': 'numerical_box', }), (0, 0, { # survey.question - 'title': _('About our ecommerce'), - 'is_page': True, - 'question_type': False - }), - (0, 0, { # survey.question - 'title': _('What do you think about our new eCommerce?'), + 'title': _('How likely are you to recommend the following products to a friend?'), 'question_type': 'matrix', 'matrix_subtype': 'simple', 'suggested_answer_ids': [ (0, 0, { # survey.question.answer - 'value': _('Strongly disagree') + 'value': _('Very Unlikely') }), (0, 0, { # survey.question.answer - 'value': _('Disagree') + 'value': _('Unlikely') }), (0, 0, { # survey.question.answer 'value': _('Neutral') }), (0, 0, { # survey.question.answer - 'value': _('Agree') + 'value': _('Likely') }), (0, 0, { # survey.question.answer - 'value': _('Strongly agree') + 'value': _('Very Likely') }) ], 'matrix_row_ids': [ (0, 0, { # survey.question.answer - 'value': _('The new layout and design is fresh and up-to-date') + 'value': _('Red Pen') }), (0, 0, { # survey.question.answer - 'value': _('It is easy to find the product that I want') + 'value': _('Blue Pen') }), (0, 0, { # survey.question.answer - 'value': _('The tool to compare the products is useful to make a choice') + 'value': _('Yellow Pen') }) ] }) @@ -109,8 +98,11 @@ class SurveyTemplate(models.Model): 'progression_mode': 'number', 'scoring_type': 'scoring_without_answers', 'users_can_go_back': True, - 'description': '
'.join([ - _('Welcome to the History certification. You will receive 2 random questions.'), + 'description': ''.join([ + _('Welcome to this Odoo certification. You will receive 2 random questions out of a pool of 3.'), + '(', + _('Cheating on your neighbors will not help!'), + ' 😁).
', _('Good luck!') ]), 'description_done': _('Thank you. We will contact you soon.'), @@ -118,68 +110,65 @@ class SurveyTemplate(models.Model): 'questions_selection': 'random', 'question_and_page_ids': [ (0, 0, { # survey.question - 'title': _('History'), + 'title': _('Odoo Certification'), 'is_page': True, 'question_type': False, 'random_questions_count': 2 }), (0, 0, { # survey.question - 'title': _('When did Genghis Khan die?'), + 'title': _('What does "ODOO" stand for?'), 'question_type': 'simple_choice', 'suggested_answer_ids': [ (0, 0, { # survey.question.answer - 'value': _('1227'), + 'value': _('It\'s a Belgian word for "Management"') + }), + (0, 0, { # survey.question.answer + 'value': _('Object-Directed Open Organization') + }), + (0, 0, { # survey.question.answer + 'value': _('Organizational Development for Operation Officers') + }), + (0, 0, { # survey.question.answer + 'value': _('It does not mean anything specific'), + 'is_correct': True, + 'answer_score': 10 + }), + ] + }), + (0, 0, { # survey.question + 'title': _('On Survey questions, one can define "placeholders". But what are they for?'), + 'question_type': 'simple_choice', + 'suggested_answer_ids': [ + (0, 0, { # survey.question.answer + 'value': _('They are a default answer, used if the participant skips the question') + }), + (0, 0, { # survey.question.answer + 'value': _('It is a small bit of text, displayed to help participants answer'), 'is_correct': True, 'answer_score': 10 }), (0, 0, { # survey.question.answer - 'value': _('1324') - }), - (0, 0, { # survey.question.answer - 'value': _('1055') + 'value': _('They are technical parameters that guarantees the responsiveness of the page') }) ] }), (0, 0, { # survey.question - 'title': _('Who is the architect of the Great Pyramid of Giza ?'), + 'title': _('What does one need to get to pass an Odoo Survey?'), 'question_type': 'simple_choice', 'suggested_answer_ids': [ (0, 0, { # survey.question.answer - 'value': _('Imhotep') - }), - (0, 0, { # survey.question.answer - 'value': _('Amenhotep') - }), - (0, 0, { # survey.question.answer - 'value': _('Hemiunu'), + 'value': _('It is an option that can be different for each Survey'), 'is_correct': True, 'answer_score': 10 }), (0, 0, { # survey.question.answer - 'value': _('Papyrus') + 'value': _('One needs to get 50% of the total score') + }), + (0, 0, { # survey.question.answer + 'value': _('One needs to answer at least half the questions correctly') }) ] }), - (0, 0, { # survey.question - 'title': _('How many years did the 100 years war last?'), - 'question_type': 'simple_choice', - 'suggested_answer_ids': [ - (0, 0, { # survey.question.answer - 'value': _('99 years') - }), - (0, 0, { # survey.question.answer - 'value': _('100 years') - }), - (0, 0, { # survey.question.answer - 'value': _('116 years'), - 'is_correct': True, - 'answer_score': 10 - }), - (0, 0, { # survey.question.answer - 'value': _('127 years') - }) - ] - }) ] } mail_template = self.env.ref('survey.mail_template_certification', raise_if_not_found=False) @@ -194,7 +183,7 @@ class SurveyTemplate(models.Model): return self.env['survey.survey'].create({ 'title': _('Live Presentation'), 'description': '
'.join([ - _('How well do you know trees? Let\'s find out!'), + _('How good of a presenter are you? Let\'s find out!'), _('But first, keep listening to the host.') ]), 'description_done': _('Thank you for your participation, hope you had a blast!'), @@ -204,66 +193,61 @@ class SurveyTemplate(models.Model): 'session_speed_rating': True, 'question_and_page_ids': [ (0, 0, { # survey.question - 'title': _('About you'), - 'is_page': True, - 'question_type': False - }), - (0, 0, { # survey.question - 'title': _('Pick a nickname'), - 'question_type': 'char_box', - 'save_as_nickname': True - }), - (0, 0, { # survey.question - 'title': _('Quiz'), - 'is_page': True, - 'question_type': False - }), - (0, 0, { # survey.question - 'title': _('In which country did the bonsai technique develop?'), + 'title': _('What is the best way to catch the attention of an audience?'), 'question_type': 'simple_choice', 'suggested_answer_ids': [ (0, 0, { # survey.question.answer - 'value': _('Japan'), + 'value': _('Speak softly so that they need to focus to hear you') + }), + (0, 0, { # survey.question.answer + 'value': _('Use a fun visual support, like a live presentation'), 'is_correct': True, 'answer_score': 20 }), (0, 0, { # survey.question.answer - 'value': _('China') - }), - (0, 0, { # survey.question.answer - 'value': _('Vietnam') - }), - (0, 0, { # survey.question.answer - 'value': _('South Korea') + 'value': _('Show them slides with a ton of text they need to read fast') }) ] }), (0, 0, { # survey.question - 'title': _('In the list below, select all the coniferous.'), + 'title': _('What is a frequent mistake public speakers do?'), + 'question_type': 'simple_choice', + 'suggested_answer_ids': [ + (0, 0, { # survey.question.answer + 'value': _('Practice in front of a mirror') + }), + (0, 0, { # survey.question.answer + 'value': _('Speak too fast'), + 'is_correct': True, + 'answer_score': 20 + }), + (0, 0, { # survey.question.answer + 'value': _('Use humor and make jokes') + }) + ] + }), + (0, 0, { # survey.question + 'title': _('Why should you consider making your presentation more fun with a small quiz?'), 'question_type': 'multiple_choice', 'suggested_answer_ids': [ (0, 0, { # survey.question.answer - 'value': _('Douglas Fir'), + 'value': _('It helps attendees focus on what you are saying'), 'is_correct': True, - 'answer_score': 5 + 'answer_score': 20 }), (0, 0, { # survey.question.answer - 'value': _('Norway Spruce'), + 'value': _('It is more engaging for your audience'), 'is_correct': True, - 'answer_score': 5 + 'answer_score': 20 }), (0, 0, { # survey.question.answer - 'value': _('European Yew'), + 'value': _('It helps attendees remember the content of your presentation'), 'is_correct': True, - 'answer_score': 5 - }), - (0, 0, { # survey.question.answer - 'value': _('Mountain Pine'), - 'is_correct': True, - 'answer_score': 5 + 'answer_score': 20 }) ] - }) + }), + ] }).action_show_sample() diff --git a/addons/survey/static/src/js/survey_renderers.js b/addons/survey/static/src/js/survey_renderers.js index 7db75e22549..b156df21921 100644 --- a/addons/survey/static/src/js/survey_renderers.js +++ b/addons/survey/static/src/js/survey_renderers.js @@ -1,55 +1,58 @@ /** @odoo-module */ -import Dialog from 'web.Dialog'; import KanbanRenderer from 'web.KanbanRenderer'; import ListRenderer from 'web.ListRenderer'; -import { qweb as QWeb, _t } from 'web.core'; +import { Markup } from 'web.utils'; + +const SurveySampleMixin = { -const SurveySampleModalMixin = { /** - * Opens a dialog allowing the user to load a sample survey - * We currently have 3 different samples to load (and one "tile" to click on - * for each in the modal). + * @override + */ + _render: function () { + // Remove "Try It" buttons of the no content helper if user can not create surveys + if (!this.activeActions.create) { + this.noContentHelp = Markup(this.noContentHelp.replaceAll( + 'Try It', + '' + )); + } + this.isLoadingSample = false; + this._super.apply(this, arguments); + }, + + /** + * Load and show the sample survey related to the clicked element, + * when there is no survey to display. + * We currently have 3 different samples to load: * - Sample Feedback Form * - Sample Certification * - Sample Live Presentation + * + * @private + * @param {Event} ev */ - _onOpenSurveySampleModalClick: function () { - const $content = $(QWeb.render('survey.survey_sample_modal_body')); - $content.find('.o_survey_sample_tile').each((_index, tile) => { - const $tile = $(tile); - $tile.on('click', async () => { - const surveySampleAction = await this._rpc({ - model: 'survey.survey', - method: $tile.data('action'), - }); - this.do_action(surveySampleAction); - }); - }); - const dialog = new Dialog(this, { - title: _t('Load a Survey'), - $content: $content, - renderFooter: false, - }); - dialog.open(); + _loadSample: function (ev) { + // Prevent loading multiple samples if double clicked + if (!this.isLoadingSample && this.activeActions.create) { + this.isLoadingSample = true; + this.do_action(this._rpc({ + model: 'survey.survey', + method: $(ev.target).closest('.o_survey_sample_container').attr('action'), + })); + } }, -} +}; -const SurveyKanbanRenderer = KanbanRenderer.extend(SurveySampleModalMixin, { - xmlDependencies: (KanbanRenderer.prototype.xmlDependencies || []).concat([ - 'survey/static/src/xml/survey_sample_modal.xml', - ]), +const SurveyKanbanRenderer = KanbanRenderer.extend(SurveySampleMixin, { events: _.extend({}, KanbanRenderer.prototype.events, { - 'click .o_survey_open_sample_modal': '_onOpenSurveySampleModalClick', + 'click .o_survey_load_sample': '_loadSample', }), }); -const SurveyListRenderer = ListRenderer.extend(SurveySampleModalMixin, { - xmlDependencies: (ListRenderer.prototype.xmlDependencies || []).concat([ - 'survey/static/src/xml/survey_sample_modal.xml', - ]), +const SurveyListRenderer = ListRenderer.extend(SurveySampleMixin, { events: _.extend({}, ListRenderer.prototype.events, { - 'click .o_survey_open_sample_modal': '_onOpenSurveySampleModalClick', + 'click .o_survey_load_sample': '_loadSample', }), }); diff --git a/addons/survey/static/src/js/tours/survey_tour.js b/addons/survey/static/src/js/tours/survey_tour.js new file mode 100644 index 00000000000..c4dff0ed223 --- /dev/null +++ b/addons/survey/static/src/js/tours/survey_tour.js @@ -0,0 +1,61 @@ +/** @odoo-module */ + +import { _t } from 'web.core'; +import { Markup } from 'web.utils'; +import tour from 'web_tour.tour'; + +tour.register('survey_tour', { + url: "/web", + rainbowManMessage: _t("Congratulations! You are now ready to collect feedback like a pro :-)"), + sequence: 225, +}, [ + ...tour.stepUtils.goToAppSteps('survey.menu_surveys', Markup(_t("Ready to change the way you gather data?"))), +{ + trigger: 'body:has(.o_survey_load_sample) .o_survey_sample_container', + content: Markup(_t("Load a sample Survey to get started quickly.")), + position: 'bottom', +}, { + trigger: 'button[name=action_test_survey]', + content: _t("Let's give it a spin!"), + position: 'bottom', +}, { + trigger: '.o_survey_start button[type=submit]', + content: _t("Let's get started!"), + position: 'bottom', +}, { + trigger: '.o_survey_simple_choice button[type=submit]', + extra_trigger: '.js_question-wrapper span:contains("How frequently")', + content: _t("Whenever you pick an answer, Odoo saves it for you."), + position: 'bottom', +}, { + trigger: '.o_survey_numerical_box button[type=submit]', + extra_trigger: '.js_question-wrapper span:contains("How many")', + content: _t("Only a single question left!"), + position: 'bottom', +}, { + trigger: '.o_survey_matrix button[value=finish]', + extra_trigger: '.js_question-wrapper span:contains("How likely")', + content: _t("Now that you are done, submit your form."), + position: 'bottom', +}, { + trigger: '.o_survey_review a', + content: _t("Let's have a look at your answers!"), + position: 'bottom', +}, { + trigger: '.alert-info a:contains("This is a Test Survey")', + content: _t("Now, use this shortcut to go back to the survey."), + position: 'bottom', +}, { + trigger: 'button[name=action_survey_user_input_completed]', + content: _t("Here, you can overview all the participations."), + position: 'bottom', +}, { + trigger: 'td[name=survey_id]', + content: _t("Let's open the survey you just submitted."), + position: 'bottom', +}, { + trigger: '.breadcrumb a:contains("Feedback Form")', + content: _t("Use the breadcrumbs to quickly go back to the dashboard."), + position: 'bottom', +} +]); diff --git a/addons/survey/static/src/xml/survey_sample_modal.xml b/addons/survey/static/src/xml/survey_sample_modal.xml deleted file mode 100644 index 9416d0b7a2e..00000000000 --- a/addons/survey/static/src/xml/survey_sample_modal.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - -
-
-
- -
- Gather feedbacks from your employees and customers. -
-
-
Feedback Form
-
-
-
- -
- Handle quiz & certifications online. -
-
-
Certification
-
-
-
- -
- Add some fun to your presentations by sharing questions live. -
-
-
Live Presentation
-
-
-
-
diff --git a/addons/survey/tests/test_survey_ui_certification.py b/addons/survey/tests/test_survey_ui_certification.py index 07649075c2c..be1d59ef787 100644 --- a/addons/survey/tests/test_survey_ui_certification.py +++ b/addons/survey/tests/test_survey_ui_certification.py @@ -15,6 +15,7 @@ class TestUiCertification(HttpCaseWithUserDemo): 'title': 'MyCompany Vendor Certification', 'access_token': '4ead4bc8-b8f2-4760-a682-1fde8daaaaac', 'access_mode': 'public', + 'questions_layout': 'one_page', 'users_can_go_back': True, 'users_login_required': True, 'scoring_type': 'scoring_with_answers', diff --git a/addons/survey/views/survey_survey_views.xml b/addons/survey/views/survey_survey_views.xml index b3178cfaadd..0461eda42b4 100644 --- a/addons/survey/views/survey_survey_views.xml +++ b/addons/survey/views/survey_survey_views.xml @@ -44,7 +44,7 @@ type="object" class="oe_stat_button" icon="fa-check-square-o"> - + @@ -180,7 +180,7 @@ survey.survey.view.tree survey.survey - + @@ -202,7 +202,7 @@ survey.survey.view.kanban survey.survey - + @@ -399,13 +399,52 @@ survey.survey kanban,tree,form,activity -

- Create a Survey -

- Surveys can serve many purposes: collect customer feedback, gather market insights, structure employee evaluations, test and certify resellers, support a live presentation, ... -

- Let's create one and share it! Not sure where to start? Load a survey -

+
+
+
+ +
+ Gather feedbacks from your employees and customers. +
+
+ + Try It +
+
+
+ +
+ Handle quiz & certifications online. +
+
+ + Try It +
+
+
+ +
+ Add some fun to your presentations by sharing questions live. +
+
+ + Try It +
+
+

+ Create a Survey +

+

+ Surveys can serve many purposes: collect customer feedback, gather market insights, structure employee evaluations, test and certify resellers, support a live presentation, ... +

+ Not sure where to start? Try a sample Survey! +

diff --git a/addons/survey/views/survey_templates.xml b/addons/survey/views/survey_templates.xml index be6de09bce4..2d8e9f6a49d 100644 --- a/addons/survey/views/survey_templates.xml +++ b/addons/survey/views/survey_templates.xml @@ -282,7 +282,7 @@ -
+
If you wish, you can review your answers
diff --git a/addons/survey/views/survey_templates_management.xml b/addons/survey/views/survey_templates_management.xml index 7888eeb3a85..18754a4ac08 100644 --- a/addons/survey/views/survey_templates_management.xml +++ b/addons/survey/views/survey_templates_management.xml @@ -80,7 +80,7 @@