diff options
| author | Odoo's Mergebot <xmo+roboto@odoo.com> | 2020-03-19 17:00:26 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-03-19 17:00:26 +0100 |
| commit | 70f3dd8a17f10e1206c9cd7fc48fd2fe904766b0 (patch) | |
| tree | fdd15f1866573bbceb7cc921b858a8384af12408 | |
| parent | 0beebad0ffa9df2295ef5104e1092dcb39f4f903 (diff) | |
| parent | 0ca0e681db14df2a029bc294f7c4c4d91686a627 (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.csv | 190 | ||||
| -rw-r--r-- | addons/survey/data/survey_demo_certification.xml | 78 | ||||
| -rw-r--r-- | addons/survey/data/survey_demo_quiz_userinput.xml | 30 | ||||
| -rw-r--r-- | addons/survey/models/survey_question.py | 76 | ||||
| -rw-r--r-- | addons/survey/models/survey_user.py | 174 | ||||
| -rw-r--r-- | addons/survey/static/tests/tours/certification_failure.js | 32 | ||||
| -rw-r--r-- | addons/survey/static/tests/tours/certification_success.js | 36 | ||||
| -rw-r--r-- | addons/survey/tests/test_survey_ui_certification.py | 54 | ||||
| -rw-r--r-- | addons/survey/views/survey_question_views.xml | 115 | ||||
| -rw-r--r-- | addons/survey/views/survey_templates_statistics.xml | 102 |
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"><p>Test your knowledge of our policies.</p></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': """<p>Test your knowledge of our policies.</p>""", + }), (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> |
