diff options
| author | David Beguin <dbe@odoo.com> | 2018-11-26 13:51:41 +0000 |
|---|---|---|
| committer | David Beguin <dbe@odoo.com> | 2019-01-23 13:28:30 +0000 |
| commit | d2ed4ba93d0a6c2e9e6982acb45b761f9f89e7a9 (patch) | |
| tree | af0741f15eea33b669e9ff69ce6b5a5ae16479e9 /addons/survey | |
| parent | f2e2b6260b3436cf894a9ea8343fb888844ed632 (diff) | |
[IMP] survey : add datetime question type
to be able to choose between asking for a date or a date with time,
a datetime question type is now added.
Task ID : 1911291
Closes PR #29054
Diffstat (limited to 'addons/survey')
| -rw-r--r-- | addons/survey/controllers/main.py | 4 | ||||
| -rw-r--r-- | addons/survey/models/survey_question.py | 34 | ||||
| -rw-r--r-- | addons/survey/models/survey_user.py | 25 | ||||
| -rw-r--r-- | addons/survey/static/src/js/survey.js | 44 | ||||
| -rw-r--r-- | addons/survey/views/survey_question_views.xml | 12 | ||||
| -rw-r--r-- | addons/survey/views/survey_templates.xml | 16 |
6 files changed, 118 insertions, 17 deletions
diff --git a/addons/survey/controllers/main.py b/addons/survey/controllers/main.py index 7fdd9d6661f..5b085d8181a 100644 --- a/addons/survey/controllers/main.py +++ b/addons/survey/controllers/main.py @@ -236,7 +236,9 @@ class Survey(http.Controller): elif answer.answer_type == 'number': answer_value = str(answer.value_number) elif answer.answer_type == 'date': - answer_value = fields.Date.to_string(answer.value_date) + answer_value = fields.Datetime.to_string(answer.value_date) + elif answer.answer_type == 'datetime': + answer_value = fields.Datetime.to_string(answer.value_datetime) elif answer.answer_type == 'suggestion' and not answer.value_suggested_row: answer_value = answer.value_suggested.id elif answer.answer_type == 'suggestion' and answer.value_suggested_row: diff --git a/addons/survey/models/survey_question.py b/addons/survey/models/survey_question.py index 56647bb2830..565f04fec5a 100644 --- a/addons/survey/models/survey_question.py +++ b/addons/survey/models/survey_question.py @@ -3,6 +3,7 @@ import logging import re +import datetime from odoo import api, fields, models, tools, _ from odoo.exceptions import ValidationError @@ -41,6 +42,7 @@ class SurveyQuestion(models.Model): ('textbox', 'Single Line Text Box'), ('numerical_box', 'Numerical Value'), ('date', 'Date'), + ('datetime', 'Datetime'), ('simple_choice', 'Multiple choice: only one answer'), ('multiple_choice', 'Multiple choice: multiple answers allowed'), ('matrix', 'Matrix')], string='Type of Question', @@ -77,6 +79,8 @@ class SurveyQuestion(models.Model): validation_max_float_value = fields.Float('Maximum value') validation_min_date = fields.Date('Minimum Date') validation_max_date = fields.Date('Maximum Date') + validation_min_datetime = fields.Datetime('Minimum Datetime') + validation_max_datetime = fields.Datetime('Maximum Datetime') validation_error_msg = fields.Char('Validation Error message', translate=True, default=lambda self: _("The answer you entered is not valid.")) # Constraints on number of answers (matrices) constr_mandatory = fields.Boolean('Mandatory Answer') @@ -91,7 +95,8 @@ class SurveyQuestion(models.Model): ('positive_len_max', 'CHECK (validation_length_max >= 0)', 'A length must be positive!'), ('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_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!') ] @api.onchange('validation_email') @@ -169,10 +174,11 @@ class SurveyQuestion(models.Model): errors.update({answer_tag: self.validation_error_msg}) return errors - @api.multi - def validate_date(self, post, answer_tag): + def date_validation(self, date_type, post, answer_tag, min_value, max_value): self.ensure_one() errors = {} + if date_type not in ('date', 'datetime'): + raise ValueError("Unexpected date type value") answer = post[answer_tag].strip() # Empty answer to mandatory question if self.constr_mandatory and not answer: @@ -180,7 +186,10 @@ class SurveyQuestion(models.Model): # Checks if user input is a date if answer: try: - dateanswer = fields.Date.from_string(answer) + if date_type == 'datetime': + dateanswer = fields.Datetime.from_string(answer) + else: + dateanswer = fields.Date.from_string(answer) except ValueError: errors.update({answer_tag: _('This is not a date')}) return errors @@ -188,10 +197,13 @@ class SurveyQuestion(models.Model): if answer and self.validation_required: # Answer is not in the right range try: - date_from_string = fields.Date.from_string + if date_type == 'datetime': + date_from_string = fields.Datetime.from_string + else: + date_from_string = fields.Date.from_string dateanswer = date_from_string(answer) - min_date = date_from_string(self.validation_min_date) - max_date = date_from_string(self.validation_max_date) + min_date = date_from_string(min_value) + max_date = date_from_string(max_value) if min_date and max_date and not (min_date <= dateanswer <= max_date): # If Minimum and Maximum Date are entered @@ -207,6 +219,14 @@ class SurveyQuestion(models.Model): return errors @api.multi + def validate_date(self, post, answer_tag): + return self.date_validation('date', post, answer_tag, self.validation_min_date, self.validation_max_date) + + @api.multi + def validate_datetime(self, post, answer_tag): + return self.date_validation('datetime', post, answer_tag, self.validation_min_datetime, self.validation_max_datetime) + + @api.multi def validate_simple_choice(self, post, answer_tag): self.ensure_one() errors = {} diff --git a/addons/survey/models/survey_user.py b/addons/survey/models/survey_user.py index d034098692b..1bdcba0c1c2 100644 --- a/addons/survey/models/survey_user.py +++ b/addons/survey/models/survey_user.py @@ -110,11 +110,13 @@ class SurveyUserInputLine(models.Model): ('text', 'Text'), ('number', 'Number'), ('date', 'Date'), + ('datetime', 'Datetime'), ('free_text', 'Free Text'), ('suggestion', 'Suggestion')], string='Answer Type') value_text = fields.Char('Text answer') value_number = fields.Float('Numerical answer') value_date = fields.Date('Date answer') + value_datetime = fields.Datetime('Datetime answer') value_free_text = fields.Text('Free Text answer') value_suggested = fields.Many2one('survey.label', string="Suggested answer") value_suggested_row = fields.Many2one('survey.label', string="Row answer") @@ -267,6 +269,29 @@ class SurveyUserInputLine(models.Model): return True @api.model + def save_line_datetime(self, user_input_id, question, post, answer_tag): + vals = { + 'user_input_id': user_input_id, + 'question_id': question.id, + 'survey_id': question.survey_id.id, + 'skipped': False + } + if answer_tag in post and post[answer_tag].strip(): + vals.update({'answer_type': 'datetime', 'value_datetime': post[answer_tag]}) + else: + vals.update({'answer_type': None, 'skipped': True}) + old_uil = self.search([ + ('user_input_id', '=', user_input_id), + ('survey_id', '=', question.survey_id.id), + ('question_id', '=', question.id) + ]) + if old_uil: + old_uil.write(vals) + else: + old_uil.create(vals) + return True + + @api.model def save_line_simple_choice(self, user_input_id, question, post, answer_tag): vals = { 'user_input_id': user_input_id, diff --git a/addons/survey/static/src/js/survey.js b/addons/survey/static/src/js/survey.js index 2b9094e37b1..9cae86adefd 100644 --- a/addons/survey/static/src/js/survey.js +++ b/addons/survey/static/src/js/survey.js @@ -79,10 +79,15 @@ if(!the_form.length) { // prefill of text/number/date boxes var input = the_form.find(".form-control[name=" + key + "]"); - if (input.attr('date')) { + if (input.hasClass('datetimepicker-input')) { // display dates in user timezone var moment_date = field_utils.parse.date(value[0]); - value = field_utils.format.date(moment_date, null, {timezone: true}); + if ($(input).closest('.input-group.date').data('questiontype') === 'datetime') { + value = field_utils.format.datetime(moment_date, null, {timezone: true}); + } + else { + value = field_utils.format.date(moment_date, null, {timezone: true}); + } } input.val(value); @@ -133,7 +138,12 @@ if(!the_form.length) { var moment_date = moment(el.value); if (moment_date) { moment_date.toJSON = function () { - return this.clone().locale('en').format('YYYY-MM-DD'); + if ($(el).closest('.input-group.date').data('questiontype') === 'datetime') { + return this.clone().utc().format('YYYY-MM-DD hh:mm:ss'); + } + else { + return this.clone().format('YYYY-MM-DD'); + } }; } var field_obj = _.findWhere(formData, {'name': el.name}); @@ -177,13 +187,33 @@ if(!the_form.length) { // frontend does not load moment locale at all. // so wait until DOM ready with locale then init datetimepicker load_locale().then(function(){ - _.each($('.input-group.date'), function(date_field){ - var minDate = $(date_field).data('mindate') || moment({ y: 1900 }); - var maxDate = $(date_field).data('maxdate') || moment().add(200, "y"); + _.each($('.input-group.date'), function(date_field){ + var disabledDates = [] + if ($(date_field).data('mindate')) { + var minDate = field_utils.format.datetime(moment($(date_field).data('mindate')), null, {timezone: true}); + } + if ($(date_field).data('maxdate')) { + var maxDate = field_utils.format.datetime(moment($(date_field).data('maxdate')), null, {timezone: true}); + } + else { + var minDate = $(date_field).data('mindate') || moment({ y: 1900 }); + var maxDate = $(date_field).data('maxdate') || moment().add(200, "y"); + } + var datetimepickerFormat = time.getLangDateFormat() + if ($(date_field).data('questiontype') === 'datetime') { + datetimepickerFormat = time.getLangDatetimeFormat() + } + else{ + maxDate = moment(maxDate).add(1, "d"); + disabledDates = [maxDate] + } $('#' + date_field.id).datetimepicker({ - format : time.getLangDateFormat(), + format : datetimepickerFormat, minDate: minDate, maxDate: maxDate, + disabledDates: disabledDates, + useCurrent: false, + viewDate: moment(new Date()).hours(0).minutes(0).seconds(0).milliseconds(0), calendarWeeks: true, icons: { time: 'fa fa-clock-o', diff --git a/addons/survey/views/survey_question_views.xml b/addons/survey/views/survey_question_views.xml index b66fc391558..b51bab4de08 100644 --- a/addons/survey/views/survey_question_views.xml +++ b/addons/survey/views/survey_question_views.xml @@ -31,12 +31,18 @@ <div attrs="{'invisible': [('question_type', '!=', 'numerical_box')]}"> <i class="fa fa-2x" role="img" aria-label="Numeric" title="Numeric">123..</i> </div> - <!-- Date and Time --> + <!-- Date --> <div attrs="{'invisible': [('question_type', '!=', 'date')]}"> <p class="o_datetime">YYYY-MM-DD <i class="fa fa-calendar fa-2x" role="img" aria-label="Calendar" title="Calendar"/> </p> </div> + <!-- Date and Time --> + <div attrs="{'invisible': [('question_type', '!=', 'datetime')]}"> + <p class="o_datetime">YYYY-MM-DD hh:mm:ss + <i class="fa fa-calendar fa-2x" role="img" aria-label="Calendar" title="Calendar"/> + </p> + </div> <!-- Multiple choice: only one answer --> <div attrs="{'invisible': [('question_type', '!=', 'simple_choice')]}" role="img" aria-label="Multiple choice with one answer" title="Multiple choice with one answer"> <div class="row"><i class="fa fa-circle-o fa-lg"/> answer</div> @@ -106,7 +112,7 @@ <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', ['textbox', 'numerical_box', 'date'])]}"> + <div colspan="2" attrs="{'invisible': [('question_type', 'not in', ['textbox', 'numerical_box', 'date', 'datetime'])]}"> <group> <field name="validation_required" attrs="{'invisible': [('validation_email', '=', True), ('question_type', '=', 'textbox')]}"/> </group> @@ -117,6 +123,8 @@ <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> diff --git a/addons/survey/views/survey_templates.xml b/addons/survey/views/survey_templates.xml index f789cfe28a9..1aca736513a 100644 --- a/addons/survey/views/survey_templates.xml +++ b/addons/survey/views/survey_templates.xml @@ -202,6 +202,7 @@ <t t-if="question.question_type == 'textbox'"><t t-call="survey.textbox"/></t> <t t-if="question.question_type == 'numerical_box'"><t t-call="survey.numerical_box"/></t> <t t-if="question.question_type == 'date'"><t t-call="survey.date"/></t> + <t t-if="question.question_type == 'datetime'"><t t-call="survey.datetime"/></t> <t t-if="question.question_type == 'simple_choice'"><t t-call="survey.simple_choice"/></t> <t t-if="question.question_type == 'multiple_choice'"><t t-call="survey.multiple_choice"/></t> <t t-if="question.question_type == 'matrix'"><t t-call="survey.matrix"/></t> @@ -257,6 +258,20 @@ </div> </template> + <template id="datetime" name="DateTime box"> + <div class="form-group"> + <div class="input-group date" t-attf-id="datetimepicker_#{question.id}" data-target-input="nearest" + t-att-data-mindate="question.validation_min_datetime" + t-att-data-maxdate="question.validation_max_datetime" + t-att-data-questiontype="question.question_type"> + <input type="text" class="form-control datetimepicker-input" t-attf-data-target="#datetimepicker_#{question.id}" t-att-name="prefix"/> + <div class="input-group-append" t-attf-data-target="#datetimepicker_#{question.id}" data-toggle="datetimepicker"> + <div class="input-group-text"><i class="fa fa-calendar"></i></div> + </div> + </div> + </div> + </template> + <template id="simple_choice" name="Simple choice"> <div t-if="question.display_mode == 'dropdown' and token" class="js_drop row"> <div class="col-lg-12"> @@ -377,6 +392,7 @@ <t t-if="question.question_type == 'textbox'"><t t-call="survey.textbox"/></t> <t t-if="question.question_type == 'numerical_box'"><t t-call="survey.numerical_box"/></t> <t t-if="question.question_type == 'date'"><t t-call="survey.date"/></t> + <t t-if="question.question_type == 'datetime'"><t t-call="survey.datetime"/></t> <t t-if="question.question_type == 'simple_choice'"><t t-call="survey.simple_choice"/></t> <t t-if="question.question_type == 'multiple_choice'"><t t-call="survey.multiple_choice"/></t> <t t-if="question.question_type == 'matrix'"><t t-call="survey.matrix"/></t> |
