diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/website_event_questions/models | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/website_event_questions/models')
4 files changed, 169 insertions, 0 deletions
diff --git a/addons/website_event_questions/models/__init__.py b/addons/website_event_questions/models/__init__.py new file mode 100644 index 00000000..14919447 --- /dev/null +++ b/addons/website_event_questions/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +from . import event_event +from . import event_question +from . import event_registration diff --git a/addons/website_event_questions/models/event_event.py b/addons/website_event_questions/models/event_event.py new file mode 100644 index 00000000..f81f5316 --- /dev/null +++ b/addons/website_event_questions/models/event_event.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + + +class EventType(models.Model): + _inherit = 'event.type' + + use_questions = fields.Boolean('Questions to Attendees') + question_ids = fields.One2many( + 'event.question', 'event_type_id', + string='Questions', copy=True) + + +class EventEvent(models.Model): + """ Override Event model to add optional questions when buying tickets. """ + _inherit = 'event.event' + + question_ids = fields.One2many( + 'event.question', 'event_id', 'Questions', copy=True, + compute='_compute_question_ids', readonly=False, store=True) + general_question_ids = fields.One2many('event.question', 'event_id', 'General Questions', + domain=[('once_per_order', '=', True)]) + specific_question_ids = fields.One2many('event.question', 'event_id', 'Specific Questions', + domain=[('once_per_order', '=', False)]) + + @api.depends('event_type_id') + def _compute_question_ids(self): + """ Update event questions from its event type. Depends are set only on + event_type_id itself to emulate an onchange. Changing event type content + itself should not trigger this method. + + When synchronizing questions: + + * lines that no answer are removed; + * type lines are added; + """ + if self._origin.question_ids: + # lines to keep: those with already sent emails or registrations + questions_tokeep_ids = self.env['event.registration.answer'].search( + [('question_id', 'in', self._origin.question_ids.ids)] + ).question_id.ids + else: + questions_tokeep_ids = [] + for event in self: + if not event.event_type_id and not event.question_ids: + event.question_ids = False + continue + + if questions_tokeep_ids: + questions_toremove = event._origin.question_ids.filtered(lambda question: question.id not in questions_tokeep_ids) + command = [(3, question.id) for question in questions_toremove] + else: + command = [(5, 0)] + if event.event_type_id.use_mail_schedule: + command += [ + (0, 0, { + 'title': question.title, + 'question_type': question.question_type, + 'sequence': question.sequence, + 'once_per_order': question.once_per_order, + 'answer_ids': [(0, 0, { + 'name': answer.name, + 'sequence': answer.sequence + }) for answer in question.answer_ids], + }) for question in event.event_type_id.question_ids + ] + event.question_ids = command diff --git a/addons/website_event_questions/models/event_question.py b/addons/website_event_questions/models/event_question.py new file mode 100644 index 00000000..4d058569 --- /dev/null +++ b/addons/website_event_questions/models/event_question.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, _ +from odoo.exceptions import UserError + + +class EventQuestion(models.Model): + _name = 'event.question' + _rec_name = 'title' + _order = 'sequence,id' + _description = 'Event Question' + + title = fields.Char(required=True, translate=True) + question_type = fields.Selection([ + ('simple_choice', 'Selection'), + ('text_box', 'Text Input')], default='simple_choice', string="Question Type", required=True) + event_type_id = fields.Many2one('event.type', 'Event Type', ondelete='cascade') + event_id = fields.Many2one('event.event', 'Event', ondelete='cascade') + answer_ids = fields.One2many('event.question.answer', 'question_id', "Answers", copy=True) + sequence = fields.Integer(default=10) + once_per_order = fields.Boolean('Ask only once per order', + help="If True, this question will be asked only once and its value will be propagated to every attendees." + "If not it will be asked for every attendee of a reservation.") + + @api.constrains('event_type_id', 'event_id') + def _constrains_event(self): + if any(question.event_type_id and question.event_id for question in self): + raise UserError(_('Question cannot belong to both the event category and itself.')) + + def write(self, vals): + """ We add a check to prevent changing the question_type of a question that already has answers. + Indeed, it would mess up the event.registration.answer (answer type not matching the question type). """ + + if 'question_type' in vals: + questions_new_type = self.filtered(lambda question: question.question_type != vals['question_type']) + if questions_new_type: + answer_count = self.env['event.registration.answer'].search_count([('question_id', 'in', questions_new_type.ids)]) + if answer_count > 0: + raise UserError(_("You cannot change the question type of a question that already has answers!")) + return super(EventQuestion, self).write(vals) + + def action_view_question_answers(self): + """ Allow analyzing the attendees answers to event questions in a convenient way: + - A graph view showing counts of each suggestions for simple_choice questions + (Along with secondary pivot and tree views) + - A tree view showing textual answers values for text_box questions. """ + self.ensure_one() + action = self.env["ir.actions.actions"]._for_xml_id("website_event_questions.action_event_registration_report") + action['domain'] = [('question_id', '=', self.id)] + if self.question_type == 'simple_choice': + action['views'] = [(False, 'graph'), (False, 'pivot'), (False, 'tree')] + elif self.question_type == 'text_box': + action['views'] = [(False, 'tree')] + return action + +class EventQuestionAnswer(models.Model): + """ Contains suggested answers to a 'simple_choice' event.question. """ + _name = 'event.question.answer' + _order = 'sequence,id' + _description = 'Event Question Answer' + + name = fields.Char('Answer', required=True, translate=True) + question_id = fields.Many2one('event.question', required=True, ondelete='cascade') + sequence = fields.Integer(default=10) diff --git a/addons/website_event_questions/models/event_registration.py b/addons/website_event_questions/models/event_registration.py new file mode 100644 index 00000000..72683374 --- /dev/null +++ b/addons/website_event_questions/models/event_registration.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models + + +class EventRegistration(models.Model): + """ Store answers on attendees. """ + _inherit = 'event.registration' + + registration_answer_ids = fields.One2many('event.registration.answer', 'registration_id', string='Attendee Answers') + +class EventRegistrationAnswer(models.Model): + """ Represents the user input answer for a single event.question """ + _name = 'event.registration.answer' + _description = 'Event Registration Answer' + + question_id = fields.Many2one( + 'event.question', ondelete='restrict', required=True, + domain="[('event_id', '=', event_id)]") + registration_id = fields.Many2one('event.registration', required=True, ondelete='cascade') + partner_id = fields.Many2one('res.partner', related='registration_id.partner_id') + event_id = fields.Many2one('event.event', related='registration_id.event_id') + question_type = fields.Selection(related='question_id.question_type') + value_answer_id = fields.Many2one('event.question.answer', string="Suggested answer") + value_text_box = fields.Text('Text answer') + + _sql_constraints = [ + ('value_check', "CHECK(value_answer_id IS NOT NULL OR COALESCE(value_text_box, '') <> '')", "There must be a suggested value or a text value.") + ] |
