summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOdoo's Mergebot <xmo+roboto@odoo.com>2020-03-19 17:00:26 +0100
committerGitHub <noreply@github.com>2020-03-19 17:00:26 +0100
commit70f3dd8a17f10e1206c9cd7fc48fd2fe904766b0 (patch)
treefdd15f1866573bbceb7cc921b858a8384af12408
parent0beebad0ffa9df2295ef5104e1092dcb39f4f903 (diff)
parent0ca0e681db14df2a029bc294f7c4c4d91686a627 (diff)
[IMP] survey: allow more question type scoring
### PURPOSE Support correct answers, scoring mechanism, and demo data on additional question types: - Numerical Value - Date - Datetime Additional improvements and fixes include: - When checking answer type, add in check to allow 0 as a valid survey answer to a question of type Numerical Value. - Include "most common" tab for question type Date in results page. - Do not show skipped answer (i.e. blank User Response value) rows in results page tables (for results of non-choice questions). ### SPECIFICATIONS **New question types scoring:** Previously only the question_types: 'simple_choice' and 'multiple_choice' could be scored and have a "correct" answer(s). This change makes it so that question_types: 'numerical_box', 'date', and 'datetime' can also have a "correct" answer and an associated 'answer_score'. Some restructuring of scoring logic was required in order to accommodate and better streamline new question_types scoring. Demo and testing data also added for these new scorable question types. New demo data includes both scored and unscored (i.e. answer_score = 0) instances for the 3 question types to ensure differing behavior is viewable in survey results. During this update, errors in existing demo data were fixed when discovered. The same demo data additions/updates were duplicated in the relevant tests. **Additional improvements/fixes:** - Answer type check: additional conditional needed to handle 0 evaluating to False even though it is a valid entry as a numerical value. - "most common" tab added only for Date since it is currently not expected to be useful for Datetime questions. Implementation is left generic for future additional question types scoring implementations. - Skipped answers were shown either as a blank value for Date, Datetime, Multiple Line Text Box, Single Line Text Box or 0.0 for Numerical Value question types. A simple check to skip these skipped lines from being shown in the results page is all that is needed. - Light rewriting of question form view to include answer-related options and choices directly in the "Answer" tab. LINKS Upgrade PR: odoo/upgrade#835 Task ID: 2061937 closes odoo/odoo#43014 Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
-rw-r--r--addons/survey/data/survey.user_input.line.csv190
-rw-r--r--addons/survey/data/survey_demo_certification.xml78
-rw-r--r--addons/survey/data/survey_demo_quiz_userinput.xml30
-rw-r--r--addons/survey/models/survey_question.py76
-rw-r--r--addons/survey/models/survey_user.py174
-rw-r--r--addons/survey/static/tests/tours/certification_failure.js32
-rw-r--r--addons/survey/static/tests/tours/certification_success.js36
-rw-r--r--addons/survey/tests/test_survey_ui_certification.py54
-rw-r--r--addons/survey/views/survey_question_views.xml115
-rw-r--r--addons/survey/views/survey_templates_statistics.xml102
10 files changed, 608 insertions, 279 deletions
diff --git a/addons/survey/data/survey.user_input.line.csv b/addons/survey/data/survey.user_input.line.csv
index f6731e4c617..1d75f750a96 100644
--- a/addons/survey/data/survey.user_input.line.csv
+++ b/addons/survey/data/survey.user_input.line.csv
@@ -1,83 +1,107 @@
-id,user_input_id:id,question_id:id,skipped,answer_type,value_char_box,value_numerical_box,value_date,value_text_box,suggested_answer_id:id,matrix_row_id:id
-survey_answer_1_p1_q1,survey_answer_1,survey_feedback_p1_q1,False,char_box,Brussels,,,,,
-survey_answer_1_p1_q2,survey_answer_1,survey_feedback_p1_q2,False,date,,,1980-01-11,,,
-survey_answer_1_p1_q3,survey_answer_1,survey_feedback_p1_q3,False,suggestion,,,,,survey_feedback_p1_q3_sug3,
-survey_answer_1_p1_q4,survey_answer_1,survey_feedback_p1_q4,False,numerical_box,,4,,,,
-survey_answer_1_p2_q1_1,survey_answer_1,survey_feedback_p2_q1,False,suggestion,,,,,survey_feedback_p2_q1_sug1,
-survey_answer_1_p2_q1_2,survey_answer_1,survey_feedback_p2_q1,False,suggestion,,,,,survey_feedback_p2_q1_sug2,
-survey_answer_1_p2_q2_1,survey_answer_1,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col3,survey_feedback_p2_q2_row1
-survey_answer_1_p2_q2_2,survey_answer_1,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col3,survey_feedback_p2_q2_row2
-survey_answer_1_p2_q2_3,survey_answer_1,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col2,survey_feedback_p2_q2_row3
-survey_answer_1_p2_q2_4,survey_answer_1,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col4,survey_feedback_p2_q2_row4
-survey_answer_1_p2_q2_5,survey_answer_1,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col2,survey_feedback_p2_q2_row5
-survey_answer_1_p2_q3,survey_answer_1,survey_feedback_p2_q3,False,text_box,,,,Thanks for the good quality of your products,,
-survey_answer_2_p1_q1,survey_answer_2,survey_feedback_p1_q1,False,char_box,Paris,,,,,
-survey_answer_2_p1_q2,survey_answer_2,survey_feedback_p1_q2,True,,,,,,,
-survey_answer_2_p1_q3,survey_answer_2,survey_feedback_p1_q3,False,suggestion,,,,,survey_feedback_p1_q3_sug2,
-survey_answer_2_p1_q4,survey_answer_2,survey_feedback_p1_q4,False,numerical_box,,10,,,,
-survey_answer_2_p2_q1_1,survey_answer_2,survey_feedback_p2_q1,False,suggestion,,,,,survey_feedback_p2_q1_sug2,
-survey_answer_2_p2_q1_2,survey_answer_2,survey_feedback_p2_q1,False,suggestion,,,,,survey_feedback_p2_q1_sug3,
-survey_answer_2_p2_q1_3,survey_answer_2,survey_feedback_p2_q1,False,suggestion,,,,,survey_feedback_p2_q1_sug4,
-survey_answer_2_p2_q2_1,survey_answer_2,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col4,survey_feedback_p2_q2_row1
-survey_answer_2_p2_q2_2,survey_answer_2,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col3,survey_feedback_p2_q2_row2
-survey_answer_2_p2_q2_3,survey_answer_2,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col3,survey_feedback_p2_q2_row3
-survey_answer_2_p2_q2_4,survey_answer_2,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col4,survey_feedback_p2_q2_row4
-survey_answer_2_p2_q2_5,survey_answer_2,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col3,survey_feedback_p2_q2_row5
-survey_answer_2_p2_q3,survey_answer_2,survey_feedback_p2_q3,False,text_box,,,,I really appreciate your products. They are awesome !!,,
-survey_answer_3_p1_q1,survey_answer_3,survey_feedback_p1_q1,False,char_box,New York,,,,,
-survey_answer_3_p1_q2,survey_answer_3,survey_feedback_p1_q2,False,date,,,1966-06-15,,,
-survey_answer_3_p1_q3,survey_answer_3,survey_feedback_p1_q3,False,suggestion,,,,,survey_feedback_p1_q3_sug4,
-survey_answer_3_p1_q4,survey_answer_3,survey_feedback_p1_q4,False,numerical_box,,1,,,,
-survey_answer_3_p2_q1_1,survey_answer_3,survey_feedback_p2_q1,False,suggestion,,,,,survey_feedback_p2_q1_sug7,
-survey_answer_3_p2_q1_2,survey_answer_3,survey_feedback_p2_q1,False,suggestion,,,,,survey_feedback_p2_q1_sug8,
-survey_answer_3_p2_q2_1,survey_answer_3,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col1,survey_feedback_p2_q2_row1
-survey_answer_3_p2_q2_2,survey_answer_3,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col2,survey_feedback_p2_q2_row2
-survey_answer_3_p2_q2_3,survey_answer_3,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col1,survey_feedback_p2_q2_row3
-survey_answer_3_p2_q2_4,survey_answer_3,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col3,survey_feedback_p2_q2_row4
-survey_answer_3_p2_q2_5,survey_answer_3,survey_feedback_p2_q2,False,suggestion,,,,,survey_feedback_p2_q2_col1,survey_feedback_p2_q2_row5
-survey_answer_3_p2_q3,survey_answer_3,survey_feedback_p2_q3,False,text_box,,,,The customizable desk received is not the one I ordered on your website and the quality is very poor ! Really disappointed.,,
-survey_vendor_certification_answer_1_p1_q1,survey_vendor_certification_answer_1,vendor_certification_page_1_question_1,False,suggestion,,,,,vendor_certification_page_1_question_1_choice_2,
-survey_vendor_certification_answer_1_p1_q2_1,survey_vendor_certification_answer_1,vendor_certification_page_1_question_2,False,suggestion,,,,,vendor_certification_page_1_question_2_choice_1,
-survey_vendor_certification_answer_1_p1_q2_2,survey_vendor_certification_answer_1,vendor_certification_page_1_question_2,False,suggestion,,,,,vendor_certification_page_1_question_2_choice_3,
-survey_vendor_certification_answer_1_p1_q2_3,survey_vendor_certification_answer_1,vendor_certification_page_1_question_2,False,suggestion,,,,,vendor_certification_page_1_question_2_choice_4,
-survey_vendor_certification_answer_1_p1_q3_1,survey_vendor_certification_answer_1,vendor_certification_page_1_question_3,False,suggestion,,,,,vendor_certification_page_1_question_3_choice_1,
-survey_vendor_certification_answer_1_p1_q3_2,survey_vendor_certification_answer_1,vendor_certification_page_1_question_3,False,suggestion,,,,,vendor_certification_page_1_question_3_choice_3,
-survey_vendor_certification_answer_1_p1_q3_3,survey_vendor_certification_answer_1,vendor_certification_page_1_question_3,False,suggestion,,,,,vendor_certification_page_1_question_3_choice_4,
-survey_vendor_certification_answer_1_p1_q4,survey_vendor_certification_answer_1,vendor_certification_page_1_question_4,False,suggestion,,,,,vendor_certification_page_1_question_4_choice_2,
-survey_vendor_certification_answer_1_p1_q5,survey_vendor_certification_answer_1,vendor_certification_page_1_question_5,False,text_box,,,,I think it misses a product but I don't know what,,
-survey_vendor_certification_answer_1_p2_q1,survey_vendor_certification_answer_1,vendor_certification_page_2_question_1,False,suggestion,,,,,vendor_certification_page_2_question_1_choice_4,
-survey_vendor_certification_answer_1_p2_q2_1,survey_vendor_certification_answer_1,vendor_certification_page_2_question_2,False,suggestion,,,,,vendor_certification_page_2_question_2_choice_1,
-survey_vendor_certification_answer_1_p2_q2_2,survey_vendor_certification_answer_1,vendor_certification_page_2_question_2,False,suggestion,,,,,vendor_certification_page_2_question_2_choice_2,
-survey_vendor_certification_answer_1_p2_q2_3,survey_vendor_certification_answer_1,vendor_certification_page_2_question_2,False,suggestion,,,,,vendor_certification_page_2_question_2_choice_4,
-survey_vendor_certification_answer_1_p2_q3,survey_vendor_certification_answer_1,vendor_certification_page_2_question_3,False,suggestion,,,,,vendor_certification_page_2_question_3_choice_3,
-survey_vendor_certification_answer_2_p1_q1,survey_vendor_certification_answer_2,vendor_certification_page_1_question_1,False,suggestion,,,,,vendor_certification_page_1_question_1_choice_2,
-survey_vendor_certification_answer_2_p1_q2_1,survey_vendor_certification_answer_2,vendor_certification_page_1_question_2,False,suggestion,,,,,vendor_certification_page_1_question_2_choice_1,
-survey_vendor_certification_answer_2_p1_q2_2,survey_vendor_certification_answer_2,vendor_certification_page_1_question_2,False,suggestion,,,,,vendor_certification_page_1_question_2_choice_3,
-survey_vendor_certification_answer_2_p1_q3_1,survey_vendor_certification_answer_2,vendor_certification_page_1_question_3,False,suggestion,,,,,vendor_certification_page_1_question_3_choice_1,
-survey_vendor_certification_answer_2_p1_q3_2,survey_vendor_certification_answer_2,vendor_certification_page_1_question_3,False,suggestion,,,,,vendor_certification_page_1_question_3_choice_3,
-survey_vendor_certification_answer_2_p1_q4,survey_vendor_certification_answer_2,vendor_certification_page_1_question_4,False,suggestion,,,,,vendor_certification_page_1_question_4_choice_2,
-survey_vendor_certification_answer_2_p1_q5,survey_vendor_certification_answer_2,vendor_certification_page_1_question_5,True,,,,,,,
-survey_vendor_certification_answer_2_p2_q1,survey_vendor_certification_answer_2,vendor_certification_page_2_question_1,False,suggestion,,,,,vendor_certification_page_2_question_1_choice_4,
-survey_vendor_certification_answer_2_p2_q2_1,survey_vendor_certification_answer_2,vendor_certification_page_2_question_2,False,suggestion,,,,,vendor_certification_page_2_question_2_choice_1,
-survey_vendor_certification_answer_2_p2_q2_2,survey_vendor_certification_answer_2,vendor_certification_page_2_question_2,False,suggestion,,,,,vendor_certification_page_2_question_2_choice_2,
-survey_vendor_certification_answer_2_p2_q2_3,survey_vendor_certification_answer_2,vendor_certification_page_1_question_2,False,suggestion,,,,,vendor_certification_page_1_question_2_choice_4,
-survey_vendor_certification_answer_2_p2_q3,survey_vendor_certification_answer_2,vendor_certification_page_2_question_3,False,suggestion,,,,,vendor_certification_page_2_question_3_choice_4,
-survey_vendor_certification_answer_3_p1_q1,survey_vendor_certification_answer_3,vendor_certification_page_1_question_1,False,suggestion,,,,,vendor_certification_page_1_question_1_choice_2,
-survey_vendor_certification_answer_3_p1_q2_1,survey_vendor_certification_answer_3,vendor_certification_page_1_question_2,False,suggestion,,,,,vendor_certification_page_1_question_2_choice_1,
-survey_vendor_certification_answer_3_p1_q2_2,survey_vendor_certification_answer_3,vendor_certification_page_1_question_2,False,suggestion,,,,,vendor_certification_page_1_question_2_choice_4,
-survey_vendor_certification_answer_3_p1_q3_1,survey_vendor_certification_answer_3,vendor_certification_page_1_question_3,False,suggestion,,,,,vendor_certification_page_1_question_3_choice_1,
-survey_vendor_certification_answer_3_p1_q3_2,survey_vendor_certification_answer_3,vendor_certification_page_1_question_3,False,suggestion,,,,,vendor_certification_page_1_question_3_choice_4,
-survey_vendor_certification_answer_3_p1_q4,survey_vendor_certification_answer_3,vendor_certification_page_1_question_4,False,suggestion,,,,,vendor_certification_page_1_question_4_choice_2,
-survey_vendor_certification_answer_3_p1_q5,survey_vendor_certification_answer_3,vendor_certification_page_1_question_5,True,,,,,,,
-survey_vendor_certification_answer_3_p2_q1,survey_vendor_certification_answer_3,vendor_certification_page_2_question_1,False,suggestion,,,,,vendor_certification_page_2_question_1_choice_4,
-survey_vendor_certification_answer_3_p2_q2_2,survey_vendor_certification_answer_3,vendor_certification_page_2_question_2,False,suggestion,,,,,vendor_certification_page_2_question_2_choice_1,
-survey_vendor_certification_answer_3_p1_q2_3,survey_vendor_certification_answer_3,vendor_certification_page_1_question_2,False,suggestion,,,,,vendor_certification_page_1_question_2_choice_4,
-survey_vendor_certification_answer_3_p2_q3,survey_vendor_certification_answer_3,vendor_certification_page_2_question_3,False,suggestion,,,,,vendor_certification_page_2_question_3_choice_2,
-survey_vendor_certification_answer_4_p1_q1,survey_vendor_certification_answer_4,vendor_certification_page_1_question_1,False,suggestion,,,,,vendor_certification_page_1_question_1_choice_1,
-survey_vendor_certification_answer_4_p1_q2,survey_vendor_certification_answer_4,vendor_certification_page_1_question_2,False,suggestion,,,,,vendor_certification_page_1_question_2_choice_3,
-survey_vendor_certification_answer_4_p1_q3,survey_vendor_certification_answer_4,vendor_certification_page_1_question_3,False,suggestion,,,,,vendor_certification_page_1_question_3_choice_2,
-survey_vendor_certification_answer_4_p1_q4,survey_vendor_certification_answer_4,vendor_certification_page_1_question_4,False,suggestion,,,,,vendor_certification_page_1_question_4_choice_4,
-survey_vendor_certification_answer_4_p1_q5,survey_vendor_certification_answer_4,vendor_certification_page_1_question_5,True,,,,,,,
-survey_vendor_certification_answer_4_p2_q1,survey_vendor_certification_answer_4,vendor_certification_page_2_question_1,False,suggestion,,,,,vendor_certification_page_2_question_1_choice_2,
-survey_vendor_certification_answer_4_p2_q2,survey_vendor_certification_answer_4,vendor_certification_page_2_question_2,False,suggestion,,,,,vendor_certification_page_2_question_2_choice_4,
-survey_vendor_certification_answer_4_p2_q3,survey_vendor_certification_answer_4,vendor_certification_page_2_question_3,False,suggestion,,,,,vendor_certification_page_2_question_3_choice_5, \ No newline at end of file
+id,user_input_id:id,question_id:id,skipped,answer_type,value_char_box,value_numerical_box,value_date,value_datetime,value_text_box,suggested_answer_id:id,matrix_row_id:id
+survey_answer_1_p1_q1,survey_answer_1,survey_feedback_p1_q1,False,char_box,Brussels,,,,,,
+survey_answer_1_p1_q2,survey_answer_1,survey_feedback_p1_q2,False,date,,,1980-01-11,,,,
+survey_answer_1_p1_q3,survey_answer_1,survey_feedback_p1_q3,False,suggestion,,,,,,survey_feedback_p1_q3_sug3,
+survey_answer_1_p1_q4,survey_answer_1,survey_feedback_p1_q4,False,numerical_box,,4,,,,,
+survey_answer_1_p2_q1_1,survey_answer_1,survey_feedback_p2_q1,False,suggestion,,,,,,survey_feedback_p2_q1_sug1,
+survey_answer_1_p2_q1_2,survey_answer_1,survey_feedback_p2_q1,False,suggestion,,,,,,survey_feedback_p2_q1_sug2,
+survey_answer_1_p2_q2_1,survey_answer_1,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col3,survey_feedback_p2_q2_row1
+survey_answer_1_p2_q2_2,survey_answer_1,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col3,survey_feedback_p2_q2_row2
+survey_answer_1_p2_q2_3,survey_answer_1,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col2,survey_feedback_p2_q2_row3
+survey_answer_1_p2_q2_4,survey_answer_1,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col4,survey_feedback_p2_q2_row4
+survey_answer_1_p2_q2_5,survey_answer_1,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col2,survey_feedback_p2_q2_row5
+survey_answer_1_p2_q3,survey_answer_1,survey_feedback_p2_q3,False,text_box,,,,,Thanks for the good quality of your products,,
+survey_answer_2_p1_q1,survey_answer_2,survey_feedback_p1_q1,False,char_box,Paris,,,,,,
+survey_answer_2_p1_q2,survey_answer_2,survey_feedback_p1_q2,True,,,,,,,,
+survey_answer_2_p1_q3,survey_answer_2,survey_feedback_p1_q3,False,suggestion,,,,,,survey_feedback_p1_q3_sug2,
+survey_answer_2_p1_q4,survey_answer_2,survey_feedback_p1_q4,False,numerical_box,,10,,,,,
+survey_answer_2_p2_q1_1,survey_answer_2,survey_feedback_p2_q1,False,suggestion,,,,,,survey_feedback_p2_q1_sug2,
+survey_answer_2_p2_q1_2,survey_answer_2,survey_feedback_p2_q1,False,suggestion,,,,,,survey_feedback_p2_q1_sug3,
+survey_answer_2_p2_q1_3,survey_answer_2,survey_feedback_p2_q1,False,suggestion,,,,,,survey_feedback_p2_q1_sug4,
+survey_answer_2_p2_q2_1,survey_answer_2,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col4,survey_feedback_p2_q2_row1
+survey_answer_2_p2_q2_2,survey_answer_2,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col3,survey_feedback_p2_q2_row2
+survey_answer_2_p2_q2_3,survey_answer_2,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col3,survey_feedback_p2_q2_row3
+survey_answer_2_p2_q2_4,survey_answer_2,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col4,survey_feedback_p2_q2_row4
+survey_answer_2_p2_q2_5,survey_answer_2,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col3,survey_feedback_p2_q2_row5
+survey_answer_2_p2_q3,survey_answer_2,survey_feedback_p2_q3,False,text_box,,,,,I really appreciate your products. They are awesome !!,,
+survey_answer_3_p1_q1,survey_answer_3,survey_feedback_p1_q1,False,char_box,New York,,,,,,
+survey_answer_3_p1_q2,survey_answer_3,survey_feedback_p1_q2,False,date,,,1966-06-15,,,,
+survey_answer_3_p1_q3,survey_answer_3,survey_feedback_p1_q3,False,suggestion,,,,,,survey_feedback_p1_q3_sug4,
+survey_answer_3_p1_q4,survey_answer_3,survey_feedback_p1_q4,False,numerical_box,,1,,,,,
+survey_answer_3_p2_q1_1,survey_answer_3,survey_feedback_p2_q1,False,suggestion,,,,,,survey_feedback_p2_q1_sug7,
+survey_answer_3_p2_q1_2,survey_answer_3,survey_feedback_p2_q1,False,suggestion,,,,,,survey_feedback_p2_q1_sug8,
+survey_answer_3_p2_q2_1,survey_answer_3,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col1,survey_feedback_p2_q2_row1
+survey_answer_3_p2_q2_2,survey_answer_3,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col2,survey_feedback_p2_q2_row2
+survey_answer_3_p2_q2_3,survey_answer_3,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col1,survey_feedback_p2_q2_row3
+survey_answer_3_p2_q2_4,survey_answer_3,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col3,survey_feedback_p2_q2_row4
+survey_answer_3_p2_q2_5,survey_answer_3,survey_feedback_p2_q2,False,suggestion,,,,,,survey_feedback_p2_q2_col1,survey_feedback_p2_q2_row5
+survey_answer_3_p2_q3,survey_answer_3,survey_feedback_p2_q3,False,text_box,,,,,The customizable desk received is not the one I ordered on your website and the quality is very poor ! Really disappointed.,,
+survey_vendor_certification_answer_1_p1_q1,survey_vendor_certification_answer_1,vendor_certification_page_1_question_1,False,suggestion,,,,,,vendor_certification_page_1_question_1_choice_2,
+survey_vendor_certification_answer_1_p1_q2_1,survey_vendor_certification_answer_1,vendor_certification_page_1_question_2,False,suggestion,,,,,,vendor_certification_page_1_question_2_choice_1,
+survey_vendor_certification_answer_1_p1_q2_2,survey_vendor_certification_answer_1,vendor_certification_page_1_question_2,False,suggestion,,,,,,vendor_certification_page_1_question_2_choice_3,
+survey_vendor_certification_answer_1_p1_q2_3,survey_vendor_certification_answer_1,vendor_certification_page_1_question_2,False,suggestion,,,,,,vendor_certification_page_1_question_2_choice_4,
+survey_vendor_certification_answer_1_p1_q3_1,survey_vendor_certification_answer_1,vendor_certification_page_1_question_3,False,suggestion,,,,,,vendor_certification_page_1_question_3_choice_1,
+survey_vendor_certification_answer_1_p1_q3_2,survey_vendor_certification_answer_1,vendor_certification_page_1_question_3,False,suggestion,,,,,,vendor_certification_page_1_question_3_choice_3,
+survey_vendor_certification_answer_1_p1_q3_3,survey_vendor_certification_answer_1,vendor_certification_page_1_question_3,False,suggestion,,,,,,vendor_certification_page_1_question_3_choice_4,
+survey_vendor_certification_answer_1_p1_q4,survey_vendor_certification_answer_1,vendor_certification_page_1_question_4,False,suggestion,,,,,,vendor_certification_page_1_question_4_choice_2,
+survey_vendor_certification_answer_1_p1_q5,survey_vendor_certification_answer_1,vendor_certification_page_1_question_5,False,text_box,,,,,I think it misses a product but I don't know what,,
+survey_vendor_certification_answer_1_p2_q1,survey_vendor_certification_answer_1,vendor_certification_page_2_question_1,False,suggestion,,,,,,vendor_certification_page_2_question_1_choice_4,
+survey_vendor_certification_answer_1_p2_q2_1,survey_vendor_certification_answer_1,vendor_certification_page_2_question_2,False,suggestion,,,,,,vendor_certification_page_2_question_2_choice_1,
+survey_vendor_certification_answer_1_p2_q2_2,survey_vendor_certification_answer_1,vendor_certification_page_2_question_2,False,suggestion,,,,,,vendor_certification_page_2_question_2_choice_2,
+survey_vendor_certification_answer_1_p2_q2_3,survey_vendor_certification_answer_1,vendor_certification_page_2_question_2,False,suggestion,,,,,,vendor_certification_page_2_question_2_choice_4,
+survey_vendor_certification_answer_1_p2_q3,survey_vendor_certification_answer_1,vendor_certification_page_2_question_3,False,suggestion,,,,,,vendor_certification_page_2_question_3_choice_3,
+survey_vendor_certification_answer_1_p3_q1,survey_vendor_certification_answer_1,vendor_certification_page_3_question_1,False,numerical_box,,30,,,,,
+survey_vendor_certification_answer_1_p3_q2,survey_vendor_certification_answer_1,vendor_certification_page_3_question_2,False,date,,,2020-01-08,,,,
+survey_vendor_certification_answer_1_p3_q3,survey_vendor_certification_answer_1,vendor_certification_page_3_question_3,False,datetime,,,,2021-01-07 01:00:01,,,
+survey_vendor_certification_answer_1_p3_q4,survey_vendor_certification_answer_1,vendor_certification_page_3_question_4,False,date,,,2020-01-01,,,,
+survey_vendor_certification_answer_1_p3_q5,survey_vendor_certification_answer_1,vendor_certification_page_3_question_5,False,datetime,,,,2021-01-01 13:00:01,,,
+survey_vendor_certification_answer_1_p3_q6,survey_vendor_certification_answer_1,vendor_certification_page_3_question_6,False,numerical_box,,1000,,,,,
+survey_vendor_certification_answer_2_p1_q1,survey_vendor_certification_answer_2,vendor_certification_page_1_question_1,False,suggestion,,,,,,vendor_certification_page_1_question_1_choice_2,
+survey_vendor_certification_answer_2_p1_q2_1,survey_vendor_certification_answer_2,vendor_certification_page_1_question_2,False,suggestion,,,,,,vendor_certification_page_1_question_2_choice_1,
+survey_vendor_certification_answer_2_p1_q2_2,survey_vendor_certification_answer_2,vendor_certification_page_1_question_2,False,suggestion,,,,,,vendor_certification_page_1_question_2_choice_3,
+survey_vendor_certification_answer_2_p1_q3_1,survey_vendor_certification_answer_2,vendor_certification_page_1_question_3,False,suggestion,,,,,,vendor_certification_page_1_question_3_choice_1,
+survey_vendor_certification_answer_2_p1_q3_2,survey_vendor_certification_answer_2,vendor_certification_page_1_question_3,False,suggestion,,,,,,vendor_certification_page_1_question_3_choice_3,
+survey_vendor_certification_answer_2_p1_q4,survey_vendor_certification_answer_2,vendor_certification_page_1_question_4,False,suggestion,,,,,,vendor_certification_page_1_question_4_choice_2,
+survey_vendor_certification_answer_2_p1_q5,survey_vendor_certification_answer_2,vendor_certification_page_1_question_5,True,,,,,,,,
+survey_vendor_certification_answer_2_p2_q1,survey_vendor_certification_answer_2,vendor_certification_page_2_question_1,False,suggestion,,,,,,vendor_certification_page_2_question_1_choice_4,
+survey_vendor_certification_answer_2_p2_q2_1,survey_vendor_certification_answer_2,vendor_certification_page_2_question_2,False,suggestion,,,,,,vendor_certification_page_2_question_2_choice_1,
+survey_vendor_certification_answer_2_p2_q2_2,survey_vendor_certification_answer_2,vendor_certification_page_2_question_2,False,suggestion,,,,,,vendor_certification_page_2_question_2_choice_2,
+survey_vendor_certification_answer_2_p2_q2_3,survey_vendor_certification_answer_2,vendor_certification_page_2_question_2,False,suggestion,,,,,,vendor_certification_page_2_question_2_choice_4,
+survey_vendor_certification_answer_2_p2_q3,survey_vendor_certification_answer_2,vendor_certification_page_2_question_3,False,suggestion,,,,,,vendor_certification_page_2_question_3_choice_4,
+survey_vendor_certification_answer_2_p3_q1,survey_vendor_certification_answer_2,vendor_certification_page_3_question_1,False,numerical_box,,30,,,,,
+survey_vendor_certification_answer_2_p3_q2,survey_vendor_certification_answer_2,vendor_certification_page_3_question_2,False,date,,,2020-01-09,,,,
+survey_vendor_certification_answer_2_p3_q3,survey_vendor_certification_answer_2,vendor_certification_page_3_question_3,False,datetime,,,,2021-01-07 01:00:01,,,
+survey_vendor_certification_answer_2_p3_q4,survey_vendor_certification_answer_2,vendor_certification_page_3_question_4,True,,,,,,,,
+survey_vendor_certification_answer_2_p3_q5,survey_vendor_certification_answer_2,vendor_certification_page_3_question_5,True,,,,,,,,
+survey_vendor_certification_answer_2_p3_q6,survey_vendor_certification_answer_2,vendor_certification_page_3_question_6,False,numerical_box,,0,,,,,
+survey_vendor_certification_answer_3_p1_q1,survey_vendor_certification_answer_3,vendor_certification_page_1_question_1,False,suggestion,,,,,,vendor_certification_page_1_question_1_choice_2,
+survey_vendor_certification_answer_3_p1_q2_1,survey_vendor_certification_answer_3,vendor_certification_page_1_question_2,False,suggestion,,,,,,vendor_certification_page_1_question_2_choice_1,
+survey_vendor_certification_answer_3_p1_q2_2,survey_vendor_certification_answer_3,vendor_certification_page_1_question_2,False,suggestion,,,,,,vendor_certification_page_1_question_2_choice_4,
+survey_vendor_certification_answer_3_p1_q3_1,survey_vendor_certification_answer_3,vendor_certification_page_1_question_3,False,suggestion,,,,,,vendor_certification_page_1_question_3_choice_1,
+survey_vendor_certification_answer_3_p1_q3_2,survey_vendor_certification_answer_3,vendor_certification_page_1_question_3,False,suggestion,,,,,,vendor_certification_page_1_question_3_choice_4,
+survey_vendor_certification_answer_3_p1_q4,survey_vendor_certification_answer_3,vendor_certification_page_1_question_4,False,suggestion,,,,,,vendor_certification_page_1_question_4_choice_2,
+survey_vendor_certification_answer_3_p1_q5,survey_vendor_certification_answer_3,vendor_certification_page_1_question_5,True,,,,,,,,
+survey_vendor_certification_answer_3_p2_q1,survey_vendor_certification_answer_3,vendor_certification_page_2_question_1,False,suggestion,,,,,,vendor_certification_page_2_question_1_choice_4,
+survey_vendor_certification_answer_3_p2_q2_2,survey_vendor_certification_answer_3,vendor_certification_page_2_question_2,False,suggestion,,,,,,vendor_certification_page_2_question_2_choice_1,
+survey_vendor_certification_answer_3_p2_q2_3,survey_vendor_certification_answer_3,vendor_certification_page_2_question_2,False,suggestion,,,,,,vendor_certification_page_2_question_2_choice_4,
+survey_vendor_certification_answer_3_p2_q3,survey_vendor_certification_answer_3,vendor_certification_page_2_question_3,False,suggestion,,,,,,vendor_certification_page_2_question_3_choice_2,
+survey_vendor_certification_answer_3_p3_q1,survey_vendor_certification_answer_3,vendor_certification_page_3_question_1,False,numerical_box,,30,,,,,
+survey_vendor_certification_answer_3_p3_q2,survey_vendor_certification_answer_3,vendor_certification_page_3_question_2,False,date,,,2020-01-08,,,,
+survey_vendor_certification_answer_3_p3_q3,survey_vendor_certification_answer_3,vendor_certification_page_3_question_3,False,datetime,,,,2021-01-06 23:59:59,,,
+survey_vendor_certification_answer_3_p3_q4,survey_vendor_certification_answer_3,vendor_certification_page_3_question_4,True,,,,,,,,
+survey_vendor_certification_answer_3_p3_q5,survey_vendor_certification_answer_3,vendor_certification_page_3_question_5,True,,,,,,,,
+survey_vendor_certification_answer_3_p3_q6,survey_vendor_certification_answer_3,vendor_certification_page_3_question_6,True,,,,,,,,
+survey_vendor_certification_answer_4_p1_q1,survey_vendor_certification_answer_4,vendor_certification_page_1_question_1,False,suggestion,,,,,,vendor_certification_page_1_question_1_choice_1,
+survey_vendor_certification_answer_4_p1_q2,survey_vendor_certification_answer_4,vendor_certification_page_1_question_2,False,suggestion,,,,,,vendor_certification_page_1_question_2_choice_3,
+survey_vendor_certification_answer_4_p1_q3,survey_vendor_certification_answer_4,vendor_certification_page_1_question_3,False,suggestion,,,,,,vendor_certification_page_1_question_3_choice_2,
+survey_vendor_certification_answer_4_p1_q4,survey_vendor_certification_answer_4,vendor_certification_page_1_question_4,False,suggestion,,,,,,vendor_certification_page_1_question_4_choice_4,
+survey_vendor_certification_answer_4_p1_q5,survey_vendor_certification_answer_4,vendor_certification_page_1_question_5,True,,,,,,,,
+survey_vendor_certification_answer_4_p2_q1,survey_vendor_certification_answer_4,vendor_certification_page_2_question_1,False,suggestion,,,,,,vendor_certification_page_2_question_1_choice_2,
+survey_vendor_certification_answer_4_p2_q2,survey_vendor_certification_answer_4,vendor_certification_page_2_question_2,False,suggestion,,,,,,vendor_certification_page_2_question_2_choice_4,
+survey_vendor_certification_answer_4_p2_q3,survey_vendor_certification_answer_4,vendor_certification_page_2_question_3,False,suggestion,,,,,,vendor_certification_page_2_question_3_choice_5,
+survey_vendor_certification_answer_4_p3_q1,survey_vendor_certification_answer_4,vendor_certification_page_3_question_1,False,numerical_box,,2,,,,,
+survey_vendor_certification_answer_4_p3_q2,survey_vendor_certification_answer_4,vendor_certification_page_3_question_2,False,date,,,2020-01-08,,,,
+survey_vendor_certification_answer_4_p3_q3,survey_vendor_certification_answer_4,vendor_certification_page_3_question_3,False,datetime,,,,2021-01-07 01:00:01,,,
+survey_vendor_certification_answer_4_p3_q4,survey_vendor_certification_answer_4,vendor_certification_page_3_question_4,False,date,,,2019-12-31,,,,
+survey_vendor_certification_answer_4_p3_q5,survey_vendor_certification_answer_4,vendor_certification_page_3_question_5,False,datetime,,,,2021-01-01 13:00:01,,,
+survey_vendor_certification_answer_4_p3_q6,survey_vendor_certification_answer_4,vendor_certification_page_3_question_6,True,,,,,,,,
diff --git a/addons/survey/data/survey_demo_certification.xml b/addons/survey/data/survey_demo_certification.xml
index e2f438b3c92..6b85585deb7 100644
--- a/addons/survey/data/survey_demo_certification.xml
+++ b/addons/survey/data/survey_demo_certification.xml
@@ -196,40 +196,40 @@
<record model="survey.question.answer" id="vendor_certification_page_2_question_1_choice_1">
<field name="question_id" ref="vendor_certification_page_2_question_1"/>
<field name="sequence">1</field>
- <field name="value">20$</field>
+ <field name="value">$20</field>
</record>
<record model="survey.question.answer" id="vendor_certification_page_2_question_1_choice_2">
<field name="question_id" ref="vendor_certification_page_2_question_1"/>
<field name="sequence">2</field>
- <field name="value">50$</field>
+ <field name="value">$50</field>
</record>
<record model="survey.question.answer" id="vendor_certification_page_2_question_1_choice_3">
<field name="question_id" ref="vendor_certification_page_2_question_1"/>
<field name="sequence">3</field>
- <field name="value">80$</field>
+ <field name="value">$80</field>
</record>
<record model="survey.question.answer" id="vendor_certification_page_2_question_1_choice_4">
<field name="question_id" ref="vendor_certification_page_2_question_1"/>
<field name="sequence">4</field>
- <field name="value">100$</field>
+ <field name="value">$100</field>
<field name="is_correct" eval="True" />
<field name="answer_score">2.0</field>
</record>
<record model="survey.question.answer" id="vendor_certification_page_2_question_1_choice_5">
<field name="question_id" ref="vendor_certification_page_2_question_1"/>
<field name="sequence">5</field>
- <field name="value">200$</field>
+ <field name="value">$200</field>
</record>
<record model="survey.question.answer" id="vendor_certification_page_2_question_1_choice_6">
<field name="question_id" ref="vendor_certification_page_2_question_1"/>
<field name="sequence">6</field>
- <field name="value">300$</field>
+ <field name="value">$300</field>
</record>
<!-- Question and predefined answer 7 -->
<record model="survey.question" id="vendor_certification_page_2_question_2">
<field name="survey_id" ref="vendor_certification" />
<field name="sequence">9</field>
- <field name="title">Select all the the products that sell for 100$ or more</field>
+ <field name="title">Select all the the products that sell for $100 or more</field>
<field name="question_type">multiple_choice</field>
<field name="column_nb">2</field>
</record>
@@ -305,6 +305,70 @@
<field name="sequence">5</field>
<field name="value">A lot overpriced</field>
</record>
+ <!-- Page 3 -->
+ <record model="survey.question" id="vendor_certification_page_3">
+ <field name="title">Policies</field>
+ <field name="survey_id" ref="vendor_certification" />
+ <field name="is_page" eval="True"/>
+ <field name="question_type" eval="False" />
+ <field name="sequence">11</field>
+ <field name="description">&lt;p&gt;Test your knowledge of our policies.&lt;/p&gt;</field>
+ </record>
+ <!-- Question and predefined answer 9 -->
+ <record model="survey.question" id="vendor_certification_page_3_question_1">
+ <field name="survey_id" ref="vendor_certification" />
+ <field name="sequence">12</field>
+ <field name="title">How many days is our money-back guarantee?</field>
+ <field name="question_type">numerical_box</field>
+ <field name="is_scored_question" eval="True" />
+ <field name="answer_numerical_box">30</field>
+ <field name="answer_score">1.0</field>
+ <field name="constr_mandatory" eval="True" />
+ </record>
+ <!-- Question and predefined answer 10 -->
+ <record model="survey.question" id="vendor_certification_page_3_question_2">
+ <field name="survey_id" ref="vendor_certification" />
+ <field name="sequence">13</field>
+ <field name="title">If a customer purchases a product on 6 January 2020, what is the latest day we expect to ship it?</field>
+ <field name="question_type">date</field>
+ <field name="is_scored_question" eval="True" />
+ <field name="answer_date">2020-01-08</field>
+ <field name="answer_score">1.0</field>
+ </record>
+ <!-- Question and predefined answer 11 -->
+ <record model="survey.question" id="vendor_certification_page_3_question_3">
+ <field name="survey_id" ref="vendor_certification" />
+ <field name="sequence">14</field>
+ <field name="title">If a customer purchases a 1 year warranty on 6 January 2020, when do we expect the warranty to expire?</field>
+ <field name="question_type">datetime</field>
+ <field name="is_scored_question" eval="True" />
+ <field name="answer_datetime">2021-01-07 00:00:01</field>
+ <field name="answer_score">1.0</field>
+ </record>
+ <!-- Question and predefined answer 12 -->
+ <record model="survey.question" id="vendor_certification_page_3_question_4">
+ <field name="survey_id" ref="vendor_certification" />
+ <field name="sequence">15</field>
+ <field name="title">What day to you think is best for us to start having an annual sale (not rated)?</field>
+ <field name="question_type">date</field>
+ <field name="answer_score">0</field>
+ </record>
+ <!-- Question and predefined answer 13 -->
+ <record model="survey.question" id="vendor_certification_page_3_question_5">
+ <field name="survey_id" ref="vendor_certification" />
+ <field name="sequence">16</field>
+ <field name="title">What day and time do you think most customers are most likely to call customer service (not rated)?</field>
+ <field name="question_type">datetime</field>
+ <field name="answer_score">0</field>
+ </record>
+ <!-- Question and predefined answer 14 -->
+ <record model="survey.question" id="vendor_certification_page_3_question_6">
+ <field name="survey_id" ref="vendor_certification" />
+ <field name="sequence">17</field>
+ <field name="title">How many chairs do you think we should aim to sell in a year (not rated)?</field>
+ <field name="question_type">numerical_box</field>
+ <field name="answer_score">0</field>
+ </record>
<record model="survey.user_input" id="survey_vendor_certification_answer_1">
<field name="survey_id" ref="survey.vendor_certification" />
diff --git a/addons/survey/data/survey_demo_quiz_userinput.xml b/addons/survey/data/survey_demo_quiz_userinput.xml
index 1330bad2187..6233598954f 100644
--- a/addons/survey/data/survey_demo_quiz_userinput.xml
+++ b/addons/survey/data/survey_demo_quiz_userinput.xml
@@ -87,12 +87,16 @@
<field name="question_id" ref="survey_demo_quiz_p3_q1"/>
<field name="answer_type">suggestion</field>
<field name="suggested_answer_id" ref="survey_demo_quiz_p3_q1_sug1"/>
+ <field name="answer_is_correct">True</field>
+ <field name="answer_score">2</field>
</record>
<record id="survey_demo_quiz_answer_1_p3_q2_l1" model="survey.user_input.line">
<field name="user_input_id" ref="survey_demo_quiz_answer_1"/>
<field name="question_id" ref="survey_demo_quiz_p3_q2"/>
<field name="answer_type">suggestion</field>
<field name="suggested_answer_id" ref="survey_demo_quiz_p3_q2_sug1"/>
+ <field name="answer_is_correct">True</field>
+ <field name="answer_score">2</field>
</record>
<record id="survey_demo_quiz_answer_1_p3_q2_l2" model="survey.user_input.line">
<field name="user_input_id" ref="survey_demo_quiz_answer_1"/>
@@ -105,6 +109,8 @@
<field name="question_id" ref="survey_demo_quiz_p3_q3"/>
<field name="answer_type">suggestion</field>
<field name="suggested_answer_id" ref="survey_demo_quiz_p3_q3_sug2"/>
+ <field name="answer_is_correct">True</field>
+ <field name="answer_score">1</field>
</record>
<record id="survey_demo_quiz_answer_1_p3_q3_l2" model="survey.user_input.line">
<field name="user_input_id" ref="survey_demo_quiz_answer_1"/>
@@ -117,6 +123,8 @@
<field name="question_id" ref="survey_demo_quiz_p3_q4"/>
<field name="answer_type">suggestion</field>
<field name="suggested_answer_id" ref="survey_demo_quiz_p3_q4_sug1"/>
+ <field name="answer_is_correct">True</field>
+ <field name="answer_score">2</field>
</record>
<record id="survey_demo_quiz_answer_1_p3_q4_l2" model="survey.user_input.line">
<field name="user_input_id" ref="survey_demo_quiz_answer_1"/>
@@ -247,6 +255,8 @@
<field name="question_id" ref="survey_demo_quiz_p3_q1"/>
<field name="answer_type">suggestion</field>
<field name="suggested_answer_id" ref="survey_demo_quiz_p3_q1_sug1"/>
+ <field name="answer_is_correct">True</field>
+ <field name="answer_score">1</field>
</record>
<record id="survey_demo_quiz_answer_2_p3_q2_l1" model="survey.user_input.line">
<field name="user_input_id" ref="survey_demo_quiz_answer_2"/>
@@ -265,6 +275,8 @@
<field name="question_id" ref="survey_demo_quiz_p3_q3"/>
<field name="answer_type">suggestion</field>
<field name="suggested_answer_id" ref="survey_demo_quiz_p3_q3_sug1"/>
+ <field name="answer_is_correct">True</field>
+ <field name="answer_score">2</field>
</record>
<record id="survey_demo_quiz_answer_2_p3_q3_l2" model="survey.user_input.line">
<field name="user_input_id" ref="survey_demo_quiz_answer_2"/>
@@ -277,6 +289,8 @@
<field name="question_id" ref="survey_demo_quiz_p3_q4"/>
<field name="answer_type">suggestion</field>
<field name="suggested_answer_id" ref="survey_demo_quiz_p3_q4_sug1"/>
+ <field name="answer_is_correct">True</field>
+ <field name="answer_score">2</field>
</record>
<record id="survey_demo_quiz_answer_2_p3_q5_l1" model="survey.user_input.line">
<field name="user_input_id" ref="survey_demo_quiz_answer_2"/>
@@ -408,24 +422,24 @@
<field name="question_id" ref="survey_demo_quiz_p3_q2"/>
<field name="answer_type">suggestion</field>
<field name="suggested_answer_id" ref="survey_demo_quiz_p3_q2_sug1"/>
- </record>
- <record id="survey_demo_quiz_answer_3_p3_q2_l2" model="survey.user_input.line">
- <field name="user_input_id" ref="survey_demo_quiz_answer_3"/>
- <field name="question_id" ref="survey_demo_quiz_p3_q2"/>
- <field name="answer_type">suggestion</field>
- <field name="suggested_answer_id" ref="survey_demo_quiz_p3_q2_sug2"/>
+ <field name="answer_is_correct">True</field>
+ <field name="answer_score">2</field>
</record>
<record id="survey_demo_quiz_answer_3_p3_q3_l1" model="survey.user_input.line">
<field name="user_input_id" ref="survey_demo_quiz_answer_3"/>
<field name="question_id" ref="survey_demo_quiz_p3_q3"/>
<field name="answer_type">suggestion</field>
<field name="suggested_answer_id" ref="survey_demo_quiz_p3_q3_sug1"/>
+ <field name="answer_is_correct">True</field>
+ <field name="answer_score">2</field>
</record>
<record id="survey_demo_quiz_answer_3_p3_q3_l2" model="survey.user_input.line">
<field name="user_input_id" ref="survey_demo_quiz_answer_3"/>
<field name="question_id" ref="survey_demo_quiz_p3_q3"/>
<field name="answer_type">suggestion</field>
<field name="suggested_answer_id" ref="survey_demo_quiz_p3_q3_sug2"/>
+ <field name="answer_is_correct">True</field>
+ <field name="answer_score">1</field>
</record>
<record id="survey_demo_quiz_answer_3_p3_q3_l3" model="survey.user_input.line">
<field name="user_input_id" ref="survey_demo_quiz_answer_3"/>
@@ -438,12 +452,16 @@
<field name="question_id" ref="survey_demo_quiz_p3_q4"/>
<field name="answer_type">suggestion</field>
<field name="suggested_answer_id" ref="survey_demo_quiz_p3_q4_sug1"/>
+ <field name="answer_is_correct">True</field>
+ <field name="answer_score">2</field>
</record>
<record id="survey_demo_quiz_answer_3_p3_q4_l2" model="survey.user_input.line">
<field name="user_input_id" ref="survey_demo_quiz_answer_3"/>
<field name="question_id" ref="survey_demo_quiz_p3_q4"/>
<field name="answer_type">suggestion</field>
<field name="suggested_answer_id" ref="survey_demo_quiz_p3_q4_sug2"/>
+ <field name="answer_is_correct">True</field>
+ <field name="answer_score">2</field>
</record>
<record id="survey_demo_quiz_answer_3_p3_q4_l3" model="survey.user_input.line">
<field name="user_input_id" ref="survey_demo_quiz_answer_3"/>
diff --git a/addons/survey/models/survey_question.py b/addons/survey/models/survey_question.py
index 1e130d749c7..54ae51e0ec1 100644
--- a/addons/survey/models/survey_question.py
+++ b/addons/survey/models/survey_question.py
@@ -80,6 +80,15 @@ class SurveyQuestion(models.Model):
('simple_choice', 'Multiple choice: only one answer'),
('multiple_choice', 'Multiple choice: multiple answers allowed'),
('matrix', 'Matrix')], string='Question Type')
+ is_scored_question = fields.Boolean(
+ 'Scored', compute='_compute_is_scored_question',
+ readonly=False, store=True, copy=True,
+ help="Include this question as part of quiz scoring. Requires an answer and answer score to be taken into account.")
+ # -- scoreable/answerable simple answer_types: numerical_box / date / datetime
+ answer_numerical_box = fields.Float('Correct numerical answer', help="Correct number answer for this question.")
+ answer_date = fields.Date('Correct date answer', help="Correct date answer for this question.")
+ answer_datetime = fields.Datetime('Correct datetime answer', help="Correct date and time answer for this question.")
+ answer_score = fields.Float('Score', help="Score value for a correct answer to this question.")
# -- char_box
save_as_email = fields.Boolean(
"Save as user email", compute='_compute_save_as_email', readonly=False, store=True, copy=True,
@@ -153,7 +162,12 @@ class SurveyQuestion(models.Model):
('validation_length', 'CHECK (validation_length_min <= validation_length_max)', 'Max length cannot be smaller than min length!'),
('validation_float', 'CHECK (validation_min_float_value <= validation_max_float_value)', 'Max value cannot be smaller than min value!'),
('validation_date', 'CHECK (validation_min_date <= validation_max_date)', 'Max date cannot be smaller than min date!'),
- ('validation_datetime', 'CHECK (validation_min_datetime <= validation_max_datetime)','Max datetime cannot be smaller than min datetime!')
+ ('validation_datetime', 'CHECK (validation_min_datetime <= validation_max_datetime)', 'Max datetime cannot be smaller than min datetime!'),
+ ('positive_answer_score', 'CHECK (answer_score >= 0)', 'An answer score for a non-multiple choice question cannot be negative!'),
+ ('scored_datetime_have_answers', "CHECK (is_scored_question != True OR question_type != 'datetime' OR answer_datetime is not null)",
+ 'All "Is a scored question = True" and "Question Type: Datetime" questions need an answer'),
+ ('scored_date_have_answers', "CHECK (is_scored_question != True OR question_type != 'date' OR answer_date is not null)",
+ 'All "Is a scored question = True" and "Question Type: Date" questions need an answer')
]
@api.onchange('validation_email')
@@ -229,7 +243,34 @@ class SurveyQuestion(models.Model):
or question.triggering_answer_id is None:
question.triggering_answer_id = False
- # Validation methods
+ @api.depends('question_type', 'scoring_type', 'answer_date', 'answer_datetime', 'answer_numerical_box')
+ def _compute_is_scored_question(self):
+ """ Computes whether a question "is scored" or not. Handles following cases:
+ - inconsistent Boolean=None edge case that breaks tests => False
+ - survey is not scored => False
+ - 'date'/'datetime'/'numerical_box' question types w/correct answer => True
+ (implied without user having to activate, except for numerical whose correct value is 0.0)
+ - 'simple_choice / multiple_choice': set to True even if logic is a bit different (coming from answers)
+ - question_type isn't scoreable (note: choice questions scoring logic handled separately) => False
+ """
+ for question in self:
+ if question.is_scored_question is None or question.scoring_type == 'no_scoring':
+ question.is_scored_question = False
+ elif question.question_type == 'date':
+ question.is_scored_question = bool(question.answer_date)
+ elif question.question_type == 'datetime':
+ question.is_scored_question = bool(question.answer_datetime)
+ elif question.question_type == 'numerical_box' and question.answer_numerical_box:
+ question.is_scored_question = True
+ elif question.question_type in ['simple_choice', 'multiple_choice']:
+ question.is_scored_question = True
+ else:
+ question.is_scored_question = False
+
+ # ------------------------------------------------------------
+ # VALIDATION
+ # ------------------------------------------------------------
+
def validate_question(self, answer, comment=None):
""" Validate question, depending on question type and parameters
for simple choice, text, date and number, answer is simply the answer of the question.
@@ -379,12 +420,12 @@ class SurveyQuestion(models.Model):
return all_questions_data
def _get_stats_data(self, user_input_lines):
- if self.question_type in ['simple_choice']:
+ if self.question_type == 'simple_choice':
return self._get_stats_data_answers(user_input_lines)
- elif self.question_type in ['multiple_choice']:
+ elif self.question_type == 'multiple_choice':
table_data, graph_data = self._get_stats_data_answers(user_input_lines)
return table_data, [{'key': self.title, 'values': graph_data}]
- elif self.question_type in ['matrix']:
+ elif self.question_type == 'matrix':
return self._get_stats_graph_data_matrix(user_input_lines)
return [line for line in user_input_lines], []
@@ -445,11 +486,15 @@ class SurveyQuestion(models.Model):
return table_data, graph_data
def _get_stats_summary_data(self, user_input_lines):
+ stats = {}
if self.question_type in ['simple_choice', 'multiple_choice']:
- return self._get_stats_summary_data_choice(user_input_lines)
- if self.question_type in ['numerical_box']:
- return self._get_stats_summary_data_numerical(user_input_lines)
- return {}
+ stats.update(self._get_stats_summary_data_choice(user_input_lines))
+ elif self.question_type == 'numerical_box':
+ stats.update(self._get_stats_summary_data_numerical(user_input_lines))
+
+ if self.question_type in ['numerical_box', 'date', 'datetime']:
+ stats.update(self._get_stats_summary_data_scored(user_input_lines))
+ return stats
def _get_stats_summary_data_choice(self, user_input_lines):
right_inputs, partial_inputs = self.env['survey.user_input'], self.env['survey.user_input']
@@ -465,8 +510,8 @@ class SurveyQuestion(models.Model):
right_inputs = user_input_lines.filtered(lambda line: line.answer_is_correct).mapped('user_input_id')
return {
'right_answers': right_answers,
- 'right_inputs': right_inputs,
- 'partial_inputs': partial_inputs,
+ 'right_inputs_count': len(right_inputs),
+ 'partial_inputs_count': len(partial_inputs),
}
def _get_stats_summary_data_numerical(self, user_input_lines):
@@ -476,7 +521,14 @@ class SurveyQuestion(models.Model):
'numerical_max': max(all_values, default=0),
'numerical_min': min(all_values, default=0),
'numerical_average': round(lines_sum / (len(all_values) or 1), 2),
- 'numerical_common_lines': collections.Counter(all_values).most_common(5),
+ }
+
+ def _get_stats_summary_data_scored(self, user_input_lines):
+ return {
+ 'common_lines': collections.Counter(
+ user_input_lines.filtered(lambda line: not line.skipped).mapped('value_%s' % self.question_type)
+ ).most_common(5) if self.question_type != 'datetime' else [],
+ 'right_inputs_count': len(user_input_lines.filtered(lambda line: line.answer_is_correct).mapped('user_input_id'))
}
diff --git a/addons/survey/models/survey_user.py b/addons/survey/models/survey_user.py
index d6ea0b1fed8..e7592caa721 100644
--- a/addons/survey/models/survey_user.py
+++ b/addons/survey/models/survey_user.py
@@ -55,13 +55,16 @@ class SurveyUserInput(models.Model):
('unique_token', 'UNIQUE (access_token)', 'An access token must be unique!'),
]
- @api.depends('user_input_line_ids.answer_score', 'user_input_line_ids.question_id', 'predefined_question_ids')
+ @api.depends('user_input_line_ids.answer_score', 'user_input_line_ids.question_id', 'predefined_question_ids.answer_score')
def _compute_scoring_values(self):
for user_input in self:
- total_possible_score = sum([
- answer_score if answer_score > 0 else 0
- for answer_score in user_input.predefined_question_ids.mapped('suggested_answer_ids.answer_score')
- ])
+ # sum(multi-choice question scores) + sum(simple answer_type scores)
+ total_possible_score = 0
+ for question in user_input.predefined_question_ids:
+ if question.question_type in ['simple_choice', 'multiple_choice']:
+ total_possible_score += sum(score for score in question.mapped('suggested_answer_ids.answer_score') if score > 0)
+ elif question.is_scored_question:
+ total_possible_score += question.answer_score
if total_possible_score == 0:
user_input.scoring_percentage = 0
@@ -335,25 +338,17 @@ class SurveyUserInput(models.Model):
'skipped': 0,
}) for user_input in self)
- scored_questions = self.mapped('predefined_question_ids').filtered(
- lambda question: question.question_type in ['simple_choice', 'multiple_choice']
- )
+ scored_questions = self.mapped('predefined_question_ids').filtered(lambda question: question.is_scored_question)
for question in scored_questions:
- question_answer_correct = question.suggested_answer_ids.filtered(lambda answer: answer.is_correct)
+ if question.question_type in ['simple_choice', 'multiple_choice']:
+ question_correct_suggested_answers = question.suggested_answer_ids.filtered(lambda answer: answer.is_correct)
for user_input in self:
- user_answer_lines_question = user_input.user_input_line_ids.filtered(lambda line: line.question_id == question)
- user_answer_correct = user_answer_lines_question.filtered(lambda line: line.answer_is_correct and not line.skipped).mapped('suggested_answer_id')
- user_answer_incorrect = user_answer_lines_question.filtered(lambda line: not line.answer_is_correct and not line.skipped)
-
- if user_answer_correct == question_answer_correct:
- res[user_input]['correct'] += 1
- elif user_answer_correct and user_answer_correct < question_answer_correct:
- res[user_input]['partial'] += 1
- if not user_answer_correct and user_answer_incorrect:
- res[user_input]['incorrect'] += 1
- if not user_answer_correct and not user_answer_incorrect:
- res[user_input]['skipped'] += 1
+ user_input_lines = user_input.user_input_line_ids.filtered(lambda line: line.question_id == question)
+ if question.question_type in ['simple_choice', 'multiple_choice']:
+ res[user_input][self._choice_question_answer_result(user_input_lines, question_correct_suggested_answers)] += 1
+ else:
+ res[user_input][self._simple_question_answer_result(user_input_lines)] += 1
return [[
{'text': _("Correct"), 'count': res[user_input]['correct']},
@@ -362,6 +357,26 @@ class SurveyUserInput(models.Model):
{'text': _("Unanswered"), 'count': res[user_input]['skipped']}
] for user_input in self]
+ def _choice_question_answer_result(self, user_input_lines, question_correct_suggested_answers):
+ correct_user_input_lines = user_input_lines.filtered(lambda line: line.answer_is_correct and not line.skipped).mapped('suggested_answer_id')
+ incorrect_user_input_lines = user_input_lines.filtered(lambda line: not line.answer_is_correct and not line.skipped)
+ if correct_user_input_lines == question_correct_suggested_answers:
+ return 'correct'
+ elif correct_user_input_lines and correct_user_input_lines < question_correct_suggested_answers:
+ return 'partial'
+ elif not correct_user_input_lines and incorrect_user_input_lines:
+ return 'incorrect'
+ else:
+ return 'skipped'
+
+ def _simple_question_answer_result(self, user_input_line):
+ if user_input_line.skipped:
+ return 'skipped'
+ elif user_input_line.answer_is_correct:
+ return 'correct'
+ else:
+ return 'incorrect'
+
# ------------------------------------------------------------
# Conditional Questions Management
# ------------------------------------------------------------
@@ -477,15 +492,7 @@ class SurveyUserInputLine(models.Model):
matrix_row_id = fields.Many2one('survey.question.answer', string="Row answer")
# scoring
answer_score = fields.Float('Score')
- answer_is_correct = fields.Boolean('Correct', compute='_compute_answer_is_correct')
-
- @api.depends('suggested_answer_id', 'question_id')
- def _compute_answer_is_correct(self):
- for answer in self:
- if answer.suggested_answer_id and answer.question_id.question_type in ['simple_choice', 'multiple_choice']:
- answer.answer_is_correct = answer.suggested_answer_id.is_correct
- else:
- answer.answer_is_correct = False
+ answer_is_correct = fields.Boolean('Correct')
@api.constrains('skipped', 'answer_type')
def _check_answer_type_skipped(self):
@@ -509,53 +516,90 @@ class SurveyUserInputLine(models.Model):
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
- score = self._get_answer_score(vals.get('user_input_id'), vals.get('suggested_answer_id'))
- if score and not vals.get('answer_score'):
- vals.update({'answer_score': score})
+ score_vals = self._get_answer_score_values(vals)
+ if not vals.get('answer_score'):
+ vals.update(score_vals)
return super(SurveyUserInputLine, self).create(vals_list)
def write(self, vals):
- score = self._get_answer_score(
- vals.get('user_input_id'),
- vals.get('suggested_answer_id'),
- compute_speed_score=False)
- if score and not vals.get('answer_score'):
- vals.update({'answer_score': score})
+ score_vals = self._get_answer_score_values(vals, compute_speed_score=False)
+ if not vals.get('answer_score'):
+ vals.update(score_vals)
return super(SurveyUserInputLine, self).write(vals)
@api.model
- def _get_answer_score(self, user_input_id, suggested_answer_id, compute_speed_score=True):
- """ If score depends on the speed of the answer, we need to compute it.
- If the user answers in less than 2 seconds, he gets 100% of the points.
- If he answers after that, he gets minimum 50% of the points.
- The 50 other % are ponderated between the time limit and the time it took him to answer.
-
- If the score does not depend on the speed, we just return the answer_score field of the
- suggested survey.question.answer. """
-
- if not suggested_answer_id:
- return None
-
- answer = self.env['survey.question.answer'].search([('id', '=', suggested_answer_id)], limit=1)
- answer_score = answer.answer_score
-
- if compute_speed_score:
+ def _get_answer_score_values(self, vals, compute_speed_score=True):
+ """ Get values for: answer_is_correct and associated answer_score.
+
+ Requires vals to contain 'answer_type', 'question_id', and 'user_input_id'.
+ Depending on 'answer_type' additional value of 'suggested_answer_id' may also be
+ required.
+
+ Calculates whether an answer_is_correct and its score based on 'answer_type' and
+ corresponding question. Handles choice (answer_type == 'suggestion') questions
+ separately from other question types. Each selected choice answer is handled as an
+ individual answer.
+
+ If score depends on the speed of the answer, it is adjusted as follows:
+ - If the user answers in less than 2 seconds, they receive 100% of the possible points.
+ - If user answers after that, they receive 50% of the possible points + the remaining
+ 50% scaled by the time limit and time taken to answer [i.e. a minimum of 50% of the
+ possible points is given to all correct answers]
+
+ Example of returned values:
+ * {'answer_is_correct': False, 'answer_score': 0} (default)
+ * {'answer_is_correct': True, 'answer_score': 2.0}
+ """
+ user_input_id = vals.get('user_input_id')
+ answer_type = vals.get('answer_type')
+ question_id = vals.get('question_id')
+ if not question_id:
+ raise ValueError(_('Computing score requires a question in arguments.'))
+ question = self.env['survey.question'].browse(int(question_id))
+
+ # default and non-scored questions
+ answer_is_correct = False
+ answer_score = 0
+
+ # record selected suggested choice answer_score (can be: pos, neg, or 0)
+ if question.question_type in ['simple_choice', 'multiple_choice']:
+ if answer_type == 'suggestion':
+ suggested_answer_id = vals.get('suggested_answer_id')
+ if suggested_answer_id:
+ question_answer = self.env['survey.question.answer'].browse(int(suggested_answer_id))
+ answer_score = question_answer.answer_score
+ answer_is_correct = question_answer.is_correct
+ # for all other scored question cases, record question answer_score (can be: pos or 0)
+ elif question.is_scored_question:
+ answer = vals.get('value_%s' % answer_type)
+ if answer_type == 'numerical_box':
+ answer = float(answer)
+ elif answer_type == 'date':
+ answer = fields.Date.from_string(answer)
+ elif answer_type == 'datetime':
+ answer = fields.Datetime.from_string(answer)
+ if answer and answer == question['answer_%s' % answer_type]:
+ answer_is_correct = True
+ answer_score = question.answer_score
+
+ if compute_speed_score and answer_score > 0:
user_input = self.env['survey.user_input'].browse(user_input_id)
session_speed_rating = user_input.exists() and user_input.is_session_answer and user_input.survey_id.session_speed_rating
- if session_speed_rating and answer.answer_score and answer.answer_score > 0:
+ if session_speed_rating:
max_score_delay = 2
- time_limit = answer.question_id.time_limit
+ time_limit = question.time_limit
now = fields.Datetime.now()
seconds_to_answer = (now - user_input.survey_id.session_question_start_time).total_seconds()
question_remaining_time = time_limit - seconds_to_answer
- if seconds_to_answer < max_score_delay: # if answered within the max_score_delay
- answer_score = answer.answer_score
- elif question_remaining_time < 0: # if no time left
- answer_score = answer.answer_score / 2
- else:
+ # if answered within the max_score_delay => leave score as is
+ if question_remaining_time < 0: # if no time left
+ answer_score /= 2
+ elif seconds_to_answer > max_score_delay:
time_limit -= max_score_delay # we remove the max_score_delay to have all possible values
- question_remaining_time -= max_score_delay
score_proportion = (time_limit - seconds_to_answer) / time_limit
- answer_score = (answer.answer_score / 2) * (1 + score_proportion)
+ answer_score = (answer_score / 2) * (1 + score_proportion)
- return answer_score
+ return {
+ 'answer_is_correct': answer_is_correct,
+ 'answer_score': answer_score
+ }
diff --git a/addons/survey/static/tests/tours/certification_failure.js b/addons/survey/static/tests/tours/certification_failure.js
index 2094ee1925f..7e87a987fd9 100644
--- a/addons/survey/static/tests/tours/certification_failure.js
+++ b/addons/survey/static/tests/tours/certification_failure.js
@@ -48,19 +48,39 @@ var failSteps = [{ // Page-1
trigger: 'div.js_question-wrapper:contains("Do you think we have missing products in our catalog") textarea',
run: "text I don't know products enough to be able to answer that",
}, { // Page-2 Question: How much do we sell our Cable Management Box?
- content: "Selecting answer '80$'",
- trigger: 'div.js_question-wrapper:contains("How much do we sell our Cable Management Box") label:contains("80$")',
-}, { // Question: Select all the the products that sell for 100$ or more
+ content: "Selecting answer '$80'",
+ trigger: 'div.js_question-wrapper:contains("How much do we sell our Cable Management Box") label:contains("$80")',
+}, { // Question: Select all the the products that sell for $100 or more
content: "Ticking answer 'Corner Desk Right Sit'",
- trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Corner Desk Right Sit")'
+ trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for $100 or more") label:contains("Corner Desk Right Sit")'
}, {
content: "Ticking answer 'Desk Combination'",
- trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Desk Combination")'
+ trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for $100 or more") label:contains("Desk Combination")'
}, {
content: "Ticking answer 'Office Chair Black'",
- trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Office Chair Black")'
+ trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for $100 or more") label:contains("Office Chair Black")'
}, { // Question: What do you think about our prices (not rated)?
trigger: 'div.js_question-wrapper:contains("What do you think about our prices") label:contains("Correctly priced")',
+}, { // Page-3 Question: How many days is our money-back guarantee?
+ content: "Inputting answer '60'",
+ trigger: 'div.js_question-wrapper:contains("How many days is our money-back guarantee") input',
+ run: 'text 60'
+}, { // Question: If a customer purchases a product on 6 January 2020, what is the latest day we expect to ship it?
+ content: "Inputting answer '01/06/2020'",
+ trigger: 'div.js_question-wrapper:contains("If a customer purchases a product on 6 January 2020, what is the latest day we expect to ship it") input',
+ run: 'text 01/06/2020'
+}, { // Question: If a customer purchases a 1 year warranty on 6 January 2020, when do we expect the warranty to expire?
+ content: "Inputting answer '01/06/2021 00:00:01'",
+ trigger: 'div.js_question-wrapper:contains("If a customer purchases a 1 year warranty on 6 January 2020, when do we expect the warranty to expire") input',
+ run: 'text 01/06/2021 00:00:01'
+}, { // Question: What day to you think is best for us to start having an annual sale (not rated)?
+ trigger: 'div.js_question-wrapper:contains("What day to you think is best for us to start having an annual sale (not rated)") input',
+}, { // Question: What day and time do you think most customers are most likely to call customer service (not rated)?
+ trigger: 'div.js_question-wrapper:contains("What day and time do you think most customers are most likely to call customer service (not rated)") input',
+}, { // Question: How many chairs do you think we should aim to sell in a year (not rated)?
+ content: "Inputting answer '0'",
+ trigger: 'div.js_question-wrapper:contains("How many chairs do you think we should aim to sell in a year (not rated)") input',
+ run: 'text 0'
}, {
content: "Finish Survey",
trigger: 'button[type="submit"]',
diff --git a/addons/survey/static/tests/tours/certification_success.js b/addons/survey/static/tests/tours/certification_success.js
index 360efb1c16b..af04fa11fb1 100644
--- a/addons/survey/static/tests/tours/certification_success.js
+++ b/addons/survey/static/tests/tours/certification_success.js
@@ -47,20 +47,44 @@ tour.register('test_certification_success', {
trigger: 'div.js_question-wrapper:contains("Do you think we have missing products in our catalog") textarea',
run: "text I think we should make more versions of the customizable desk, it's such an amazing product!",
}, { // Page-2 Question: How much do we sell our Cable Management Box?
- content: "Selecting answer '80$' (wrong one)",
- trigger: 'div.js_question-wrapper:contains("How much do we sell our Cable Management Box") label:contains("80$")',
- }, { // Question: Select all the the products that sell for 100$ or more
+ content: "Selecting answer '$80' (wrong one)",
+ trigger: 'div.js_question-wrapper:contains("How much do we sell our Cable Management Box") label:contains("$80")',
+ }, { // Question: Select all the the products that sell for $100 or more
content: "Ticking answer 'Corner Desk Right Sit'",
- trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Corner Desk Right Sit")'
+ trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for $100 or more") label:contains("Corner Desk Right Sit")'
}, {
content: "Ticking answer 'Desk Combination'",
- trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Desk Combination")'
+ trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for $100 or more") label:contains("Desk Combination")'
}, {
content: "Ticking answer 'Large Desk'",
- trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for 100$ or more") label:contains("Large Desk")'
+ trigger: 'div.js_question-wrapper:contains("Select all the the products that sell for $100 or more") label:contains("Large Desk")'
}, { // Question: What do you think about our prices (not rated)?
content: "Selecting answer 'Underpriced'",
trigger: 'div.js_question-wrapper:contains("What do you think about our prices") label:contains("Underpriced")',
+ }, { // Page-3 Question: How many days is our money-back guarantee?
+ content: "Inputting answer '30'",
+ trigger: 'div.js_question-wrapper:contains("How many days is our money-back guarantee") input',
+ run: 'text 30'
+ }, { // Question: If a customer purchases a product on 6 January 2020, what is the latest day we expect to ship it?
+ content: "Inputting answer '01/08/2020'",
+ trigger: 'div.js_question-wrapper:contains("If a customer purchases a product on 6 January 2020, what is the latest day we expect to ship it") input',
+ run: 'text 01/08/2020'
+ }, { // Question: If a customer purchases a 1 year warranty on 6 January 2020, when do we expect the warranty to expire?
+ content: "Inputting answer '01/07/2021 00:00:01'",
+ trigger: 'div.js_question-wrapper:contains("If a customer purchases a 1 year warranty on 6 January 2020, when do we expect the warranty to expire") input',
+ run: 'text 01/07/2021 00:00:01'
+ }, { // Question: What day to you think is best for us to start having an annual sale (not rated)?
+ content: "Inputting answer '01/01/2021'",
+ trigger: 'div.js_question-wrapper:contains("What day to you think is best for us to start having an annual sale (not rated)") input',
+ run: 'text 01/01/2021'
+ }, { // Question: What day and time do you think most customers are most likely to call customer service (not rated)?
+ content: "Inputting answer '01/01/2021 13:00:01'",
+ trigger: 'div.js_question-wrapper:contains("What day and time do you think most customers are most likely to call customer service (not rated)") input',
+ run: 'text 01/01/2021 13:00:01'
+ }, { // Question: How many chairs do you think we should aim to sell in a year (not rated)?
+ content: "Inputting answer '1000'",
+ trigger: 'div.js_question-wrapper:contains("How many chairs do you think we should aim to sell in a year (not rated)") input',
+ run: 'text 1000'
}, {
content: "Finish Survey",
trigger: 'button[type="submit"]',
diff --git a/addons/survey/tests/test_survey_ui_certification.py b/addons/survey/tests/test_survey_ui_certification.py
index da8d3b74658..ecb473a2d1d 100644
--- a/addons/survey/tests/test_survey_ui_certification.py
+++ b/addons/survey/tests/test_survey_ui_certification.py
@@ -150,29 +150,29 @@ class TestUiCertification(HttpCaseWithUserDemo):
'constr_mandatory': True,
'suggested_answer_ids': [
(0, 0, {
- 'value': '20$',
+ 'value': '$20',
'sequence': 1,
}), (0, 0, {
- 'value': '50$',
+ 'value': '$50',
'sequence': 2,
}), (0, 0, {
- 'value': '80$',
+ 'value': '$80',
'sequence': 3,
}), (0, 0, {
- 'value': '100$',
+ 'value': '$100',
'sequence': 4,
'is_correct': True,
'answer_score': 2,
}), (0, 0, {
- 'value': '200$',
+ 'value': '$200',
'sequence': 5,
}), (0, 0, {
- 'value': '300$',
+ 'value': '$300',
'sequence': 6,
})
]
}), (0, 0, {
- 'title': 'Select all the the products that sell for 100$ or more',
+ 'title': 'Select all the the products that sell for $100 or more',
'sequence': 9,
'question_type': 'multiple_choice',
'column_nb': '2',
@@ -229,6 +229,46 @@ class TestUiCertification(HttpCaseWithUserDemo):
'sequence': 5,
})
]
+ }), (0, 0, {
+ 'title': 'Policies',
+ 'sequence': 11,
+ 'is_page': True,
+ 'question_type': False,
+ 'description': """&lt;p&gt;Test your knowledge of our policies.&lt;/p&gt;""",
+ }), (0, 0, {
+ 'title': 'How many days is our money-back guarantee?',
+ 'sequence': 12,
+ 'question_type': 'numerical_box',
+ 'constr_mandatory': True,
+ 'is_scored_question': True,
+ 'answer_numerical_box': 30,
+ 'answer_score': 1,
+ }), (0, 0, {
+ 'title': 'If a customer purchases a product on 6 January 2020, what is the latest day we expect to ship it?',
+ 'sequence': 13,
+ 'question_type': 'date',
+ 'is_scored_question': True,
+ 'answer_date': '2020-01-08',
+ 'answer_score': 1,
+ }), (0, 0, {
+ 'title': 'If a customer purchases a 1 year warranty on 6 January 2020, when do we expect the warranty to expire?',
+ 'sequence': 14,
+ 'question_type': 'datetime',
+ 'is_scored_question': True,
+ 'answer_datetime': '2021-01-07 00:00:01',
+ 'answer_score': 1,
+ }), (0, 0, {
+ 'title': 'What day to you think is best for us to start having an annual sale (not rated)?',
+ 'sequence': 15,
+ 'question_type': 'date',
+ }), (0, 0, {
+ 'title': 'What day and time do you think most customers are most likely to call customer service (not rated)?',
+ 'sequence': 16,
+ 'question_type': 'datetime',
+ }), (0, 0, {
+ 'title': 'How many chairs do you think we should aim to sell in a year (not rated)?',
+ 'sequence': 17,
+ 'question_type': 'numerical_box',
})
]
})
diff --git a/addons/survey/views/survey_question_views.xml b/addons/survey/views/survey_question_views.xml
index 90f43834762..09734b61221 100644
--- a/addons/survey/views/survey_question_views.xml
+++ b/addons/survey/views/survey_question_views.xml
@@ -8,8 +8,10 @@
<field name="arch" type="xml">
<form string="Survey Question" create="false">
<field name="is_page" invisible="1"/>
+ <field name="page_id" invisible="1" required="False"/>
<field name="survey_id" invisible="1"/>
<field name="sequence" invisible="1"/>
+ <field name="scoring_type" invisible="1"/>
<sheet>
<div class="oe_title" style="width: 100%;">
<label for="title" string="Section" attrs="{'invisible': [('is_page', '=', False)]}"/>
@@ -96,63 +98,76 @@
</group>
<notebook>
<page string="Answers" name="answers" attrs="{'invisible': [('is_page', '=', True)]}">
- <field name="validation_email" attrs="{'invisible': [('question_type', '!=', 'char_box')]}"/>
- <label for="validation_email" attrs="{'invisible': [('question_type', '!=', 'char_box')]}"/><br/>
- <field name="save_as_email" attrs="{'invisible': ['|', ('question_type', '!=', 'char_box'), ('validation_email', '=', False)]}"/>
- <label for="save_as_email" attrs="{'invisible': ['|', ('question_type', '!=', 'char_box'), ('validation_email', '=', False)]}"/>
- <div attrs="{'invisible': [('question_type', '!=', 'char_box')]}">
- <field name="save_as_nickname"/>
- <label for="save_as_nickname"/>
+ <div class="row">
+ <div class="col-6"
+ attrs="{'invisible': [('question_type', 'not in', ['char_box', 'numerical_box', 'date', 'datetime'])]}">
+ <div attrs="{'invisible': [('question_type', '!=', 'char_box')]}">
+ <field name="validation_email" nolabel="1"/>
+ <label for="validation_email"/><br />
+
+ <field name="save_as_email" nolabel="1" attrs="{'invisible': [('validation_email', '=', False)]}"/>
+ <label for="save_as_email" attrs="{'invisible': [('validation_email', '=', False)]}"/>
+ <br attrs="{'invisible': [('validation_email', '=', False)]}"/>
+
+ <field name="save_as_nickname" nolabel="1"/>
+ <label for="save_as_nickname"/>
+ </div>
+ <div>
+ <field name="validation_required" nolabel="1"/>
+ <label for="validation_required"/>
+ <group attrs="{'invisible': [('validation_required', '=', False)]}">
+ <field name="validation_length_min" attrs="{'invisible': [('question_type', '!=', 'char_box')]}"/>
+ <field name="validation_length_max" attrs="{'invisible': [('question_type', '!=', 'char_box')]}"/>
+ <field name="validation_min_float_value" attrs="{'invisible': [('question_type', '!=', 'numerical_box')]}"/>
+ <field name="validation_max_float_value" attrs="{'invisible': [('question_type', '!=', 'numerical_box')]}"/>
+ <field name="validation_min_date" attrs="{'invisible': [('question_type', '!=', 'date')]}"/>
+ <field name="validation_max_date" attrs="{'invisible': [('question_type', '!=', 'date')]}"/>
+ <field name="validation_min_datetime" widget="datetime" attrs="{'invisible': [('question_type', '!=', 'datetime')]}"/>
+ <field name="validation_max_datetime" widget="datetime" attrs="{'invisible': [('question_type', '!=', 'datetime')]}"/>
+ <field name="validation_error_msg"/>
+ </group>
+ </div>
+ </div>
+
+ <div class="col-6" attrs="{'invisible': [
+ '|', ('scoring_type', '=', 'no_scoring'),
+ ('question_type', 'not in', ['numerical_box', 'date', 'datetime'])]
+ }">
+ <group>
+ <field name="answer_numerical_box" string="Correct Answer" attrs="{'invisible': [('question_type', '!=', 'numerical_box')]}"/>
+ <field name="answer_date" string="Correct Answer" attrs="{'invisible': [('question_type', '!=', 'date')]}"/>
+ <field name="answer_datetime" string="Correct Answer" attrs="{'invisible': [('question_type', '!=', 'datetime')]}"/>
+ <field name="is_scored_question"/>
+ <field name="answer_score"/>
+ </group>
+ </div>
</div>
- <field name="page_id" invisible="1" required="0"/>
- <field name="survey_id" invisible="1" readonly="1"/>
- <field name="scoring_type" invisible="1"/>
- <separator />
- <label for="suggested_answer_ids" string="Columns of the Matrix" attrs="{'invisible': [('question_type', '!=', 'matrix')]}" />
- <field name="suggested_answer_ids" string="Type of answers" context="{'default_question_id': active_id}" attrs="{'invisible': [('question_type', 'not in', ['simple_choice', 'multiple_choice', 'matrix'])]}">
- <tree editable="bottom">
- <field name="sequence" widget="handle"/>
- <field name="value" string="Choices"/>
- <field name="value_image" options="{'accepted_file_extensions': 'image/*'}"
- attrs="{'column_invisible': ['|', ('parent.allow_value_image', '=', False), ('parent.question_type', '=', 'matrix')]}"/>
- <field name="is_correct" attrs="{'column_invisible': ['|', ('parent.scoring_type', '=', 'no_scoring'), ('parent.question_type', '=', 'matrix')]}"/>
- <field name="answer_score" attrs="{'column_invisible': ['|', ('parent.scoring_type', '=', 'no_scoring'), ('parent.question_type', '=', 'matrix')]}"/>
- </tree>
- </field>
- <separator />
- <label for="matrix_row_ids" attrs="{'invisible': [('question_type', '!=', 'matrix')]}" />
- <field name="matrix_row_ids" context="{'default_matrix_question_id': active_id}" attrs="{'invisible': [('question_type', '!=', 'matrix')]}">
- <tree editable="bottom">
- <field name="sequence" widget="handle"/>
- <field name="value" string="Rows"/>
- </tree>
- </field>
+ <group attrs="{'invisible': [('question_type', 'not in', ['simple_choice', 'multiple_choice', 'matrix'])]}">
+ <field name="suggested_answer_ids" string="Answers" context="{'default_question_id': active_id}">
+ <tree editable="bottom">
+ <field name="sequence" widget="handle"/>
+ <field name="value" string="Choices"/>
+ <field name="value_image" options="{'accepted_file_extensions': 'image/*'}"
+ attrs="{'column_invisible': ['|', ('parent.allow_value_image', '=', False), ('parent.question_type', '=', 'matrix')]}"/>
+ <field name="is_correct" attrs="{'column_invisible': ['|', ('parent.scoring_type', '=', 'no_scoring'), ('parent.question_type', '=', 'matrix')]}"/>
+ <field name="answer_score" attrs="{'column_invisible': ['|', ('parent.scoring_type', '=', 'no_scoring'), ('parent.question_type', '=', 'matrix')]}"/>
+ </tree>
+ </field>
+ </group>
+ <group attrs="{'invisible': [('question_type', '!=', 'matrix')]}">
+ <field name="matrix_row_ids" context="{'default_matrix_question_id': active_id}" attrs="{'invisible': [('question_type', '!=', 'matrix')]}">
+ <tree editable="bottom">
+ <field name="sequence" widget="handle"/>
+ <field name="value" string="Rows"/>
+ </tree>
+ </field>
+ </group>
</page>
<page string="Description" name="survey_description">
<field name="description" widget="html"/>
</page>
<page string="Options" name="options" attrs="{'invisible': [('is_page', '=', True)]}">
<group string="Constraints">
- <group colspan="2" col="4">
- <field name="constr_mandatory" string="Mandatory Answer"/>
- <field name="constr_error_msg" attrs="{'invisible': [('constr_mandatory', '=', False)]}"/>
- </group>
- <div colspan="2" attrs="{'invisible': [('question_type', 'not in', ['char_box', 'numerical_box', 'date', 'datetime'])]}">
- <group>
- <field name="validation_required" attrs="{'invisible': [('validation_email', '=', True), ('question_type', '=', 'char_box')]}"/>
- </group>
- <group col="4" attrs="{'invisible': [('validation_required', '=', False)]}">
- <field name="validation_length_min" attrs="{'invisible': [('question_type', '!=', 'char_box')]}"/>
- <field name="validation_length_max" attrs="{'invisible': [('question_type', '!=', 'char_box')]}"/>
- <field name="validation_min_float_value" attrs="{'invisible': [('question_type', '!=', 'numerical_box')]}"/>
- <field name="validation_max_float_value" attrs="{'invisible': [('question_type', '!=', 'numerical_box')]}"/>
- <field name="validation_min_date" attrs="{'invisible': [('question_type', '!=', 'date')]}"/>
- <field name="validation_max_date" attrs="{'invisible': [('question_type', '!=', 'date')]}"/>
- <field name="validation_min_datetime" widget="datetime" attrs="{'invisible': [('question_type', '!=', 'datetime')]}"/>
- <field name="validation_max_datetime" widget="datetime" attrs="{'invisible': [('question_type', '!=', 'datetime')]}"/>
- <field name="validation_error_msg" colspan="4"/>
- </group>
- </div>
<group>
<field name="matrix_subtype" attrs="{'invisible':[('question_type','not in',['matrix'])],'required':[('question_type','=','matrix')]}"/>
</group>
diff --git a/addons/survey/views/survey_templates_statistics.xml b/addons/survey/views/survey_templates_statistics.xml
index d4492788614..c738e6a80ba 100644
--- a/addons/survey/views/survey_templates_statistics.xml
+++ b/addons/survey/views/survey_templates_statistics.xml
@@ -65,7 +65,7 @@
</template>
<template id="survey_page_statistics_question" name="Question: result statistics">
- <t t-set="question_scoring" t-value="survey.scoring_type in ['scoring_with_answers', 'scoring_without_answers'] and question.question_type in ['simple_choice', 'multiple_choice']"/>
+ <t t-set="question_scoring" t-value="survey.scoring_type in ['scoring_with_answers', 'scoring_without_answers']"/>
<t t-set="comment_lines" t-value="question_data['comment_line_ids']"/>
<t t-set="graph_data" t-value="question_data['graph_data']"/>
<t t-set="table_data" t-value="question_data['table_data']"/>
@@ -75,13 +75,33 @@
<div class="mr-auto">
<h5 t-field="question.title" class="mb-1"/>
<div t-if="question_scoring">
- <t t-if="len(question_data['right_answers']) >= 1">
- <span t-if="len(question_data['right_answers']) == 1">Right answer: </span>
- <span t-if="len(question_data['right_answers']) > 1">Right answers: </span>
+ <t t-if="question.question_type in ['simple_choice', 'multiple_choice']">
+ <t t-if="len(question_data['right_answers']) >= 1">
+ <span t-if="len(question_data['right_answers']) == 1">Right answer: </span>
+ <span t-if="len(question_data['right_answers']) > 1">Right answers: </span>
+ <strong>
+ <t t-foreach="question_data['right_answers']" t-as="answer">
+ <span t-if="answer_index != 0">, </span><span t-esc="answer.value"/>
+ </t>
+ </strong>
+ </t>
+ </t>
+ <t t-if="question.is_scored_question">
+ <span>Right answer:</span>
<strong>
- <t t-foreach="question_data['right_answers']" t-as="answer">
- <span t-if="answer_index != 0">, </span><span t-esc="answer.value"/>
+ <t t-if="question.question_type == 'numerical_box'">
+ <span t-esc="question.answer_numerical_box"/>
+ </t>
+ <t t-if="question.question_type == 'date'">
+ <span t-field="question.answer_date"/>
</t>
+ <t t-if="question.question_type == 'datetime'">
+ <span t-field="question.answer_datetime"/>
+ </t>
+ </strong><br/>
+ <span>Score:</span>
+ <strong>
+ <span t-esc="question.answer_score"/>
</strong>
</t>
</div>
@@ -93,10 +113,15 @@
</t>
<!-- Scoring info -->
<t t-if="question_scoring">
- <span class="badge badge-success ml-3"><span t-esc="len(question_data['right_inputs'])"></span> Correct</span>
- <span class="badge badge-warning ml-1" t-if="question.question_type == 'multiple_choice'">
- <span t-esc="len(question_data['partial_inputs'])"></span> Partial
- </span>
+ <t t-if="question.question_type in ['simple_choice', 'multiple_choice']">
+ <span class="badge badge-success ml-3"><span t-esc="question_data['right_inputs_count']"></span> Correct</span>
+ <span class="badge badge-warning ml-1" t-if="question.question_type == 'multiple_choice'">
+ <span t-esc="question_data['partial_inputs_count']"></span> Partial
+ </span>
+ </t>
+ <t t-if="question.is_scored_question">
+ <span class="badge badge-success ml-3"><span t-esc="question_data['right_inputs_count']"></span> Correct</span>
+ </t>
</t>
<!-- Inputs info -->
<span class="badge badge-info ml-3"><span t-esc="len(question_data['answer_input_done_ids'])"></span> Answered</span>
@@ -105,23 +130,22 @@
<!-- Question Description -->
<div class="ml-3 text-muted" t-field="question.description"/>
-
- <t t-if="question.question_type in ['text_box', 'char_box', 'date', 'datetime']">
- <t t-call="survey.question_result_text"/>
- </t>
- <t t-elif="question.question_type in ['numerical_box']">
- <t t-call="survey.question_result_number"></t>
- </t>
- <t t-elif="question.question_type in ['simple_choice', 'multiple_choice']">
- <t t-call="survey.question_result_choice"></t>
- </t>
- <t t-elif="question.question_type in ['matrix']">
- <t t-call="survey.question_result_matrix"></t>
- </t>
+ <t t-if="question.question_type in ['text_box', 'char_box', 'datetime']">
+ <t t-call="survey.question_result_text"/>
+ </t>
+ <t t-elif="question.question_type in ['numerical_box', 'date']">
+ <t t-call="survey.question_result_number_or_date"></t>
+ </t>
+ <t t-elif="question.question_type in ['simple_choice', 'multiple_choice']">
+ <t t-call="survey.question_result_choice"></t>
+ </t>
+ <t t-elif="question.question_type in ['matrix']">
+ <t t-call="survey.question_result_matrix"></t>
+ </t>
</div>
</template>
- <template id="question_result_text" name="Question: text result (text_box, char_box, date, datetime)">
+ <template id="question_result_text" name="Question: text result (text_box, char_box, datetime)">
<table class="table table-hover table-sm" t-att-id="'survey_table_question_%d' % question.id">
<thead>
<tr>
@@ -149,10 +173,6 @@
<span t-if="no_print_url" t-field="input_line.value_char_box" />
<a t-else="" t-att-href="input_line.user_input_id.get_print_url()" t-field="input_line.value_char_box"></a>
</t>
- <t t-if="question.question_type == 'date'">
- <span t-if="no_print_url" t-field="input_line.value_date" />
- <a t-else="" t-att-href="input_line.user_input_id.get_print_url()" t-field="input_line.value_date"></a>
- </t>
<t t-if="question.question_type == 'datetime'">
<span t-if="no_print_url" t-field="input_line.value_datetime" />
<a t-else="" t-att-href="input_line.user_input_id.get_print_url()" t-field="input_line.value_datetime"></a>
@@ -165,12 +185,14 @@
<t t-call="survey.question_table_pagination"/>
</template>
- <template id="question_result_number" name="Question: number result (numerical_box)">
- <span class="float-right mt8">
- <span class="badge badge-secondary only_left_radius">Maximum </span> <span class="badge badge-success only_right_radius" t-esc="question_data['numerical_max']"></span>
- <span class="badge badge-secondary only_left_radius">Minimum </span> <span class="badge badge-danger only_right_radius" t-esc="question_data['numerical_min']"></span>
- <span class="badge badge-secondary only_left_radius">Average </span> <span class="badge badge-warning only_right_radius" t-esc="question_data['numerical_average']"></span>
- </span>
+ <template id="question_result_number_or_date" name="Question: number or date result (numerical_box or date)">
+ <t t-if="question.question_type == 'numerical_box'">
+ <span class="float-right mt8">
+ <span class="badge badge-secondary only_left_radius">Maximum </span> <span class="badge badge-success only_right_radius" t-esc="question_data['numerical_max']"></span>
+ <span class="badge badge-secondary only_left_radius">Minimum </span> <span class="badge badge-danger only_right_radius" t-esc="question_data['numerical_min']"></span>
+ <span class="badge badge-secondary only_left_radius">Average </span> <span class="badge badge-warning only_right_radius" t-esc="question_data['numerical_average']"></span>
+ </span>
+ </t>
<ul class="nav nav-tabs d-print-none" role="tablist">
<li class="nav-item">
@@ -198,8 +220,11 @@
</tr>
</thead>
<tbody>
- <tr t-foreach="question_data['numerical_common_lines']" t-as="common_line">
- <td><span t-esc="common_line[0]"></span></td>
+ <tr t-foreach="question_data['common_lines']" t-as="common_line">
+ <td>
+ <span t-if="question.question_type == 'numerical_box'" t-esc="common_line[0]"/>
+ <span t-if="question.question_type == 'date'" t-esc="common_line[0]" t-options='{"widget": "date"}'/>
+ </td>
<td><span t-esc="common_line[1]"></span></td>
</tr>
</tbody>
@@ -224,7 +249,10 @@
</a>
</t>
</td>
- <td><span t-field="input_line.value_numerical_box"></span><br/></td>
+ <td>
+ <a t-if="question.question_type == 'numerical_box'" t-att-href="input_line.user_input_id.get_print_url()" t-field="input_line.value_numerical_box"/>
+ <a t-if="question.question_type == 'date'" t-att-href="input_line.user_input_id.get_print_url()" t-field="input_line.value_date"/>
+ </td>
</tr>
</t>
</tbody>