From ebbe0cac038a5fa394a7377a263bf32b4e5038e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 25 Oct 2018 15:13:06 +0000 Subject: [PATCH 1/2] [REF] survey: break dependency from survey composer on mail composer Purpose of this commit is to clean survey composer model. It currently inherits from mail.compose.message which also inherits from mail.message. That means a lot of fields and behavior coming from both models are present on the survey composer. Most of them are not necessary as * send_mail method of mail composer is overriden and super is not called. Nothing from the complex behavior of mail.compose.message is used; * templates are just basically supported in survey, notably mass mailing or mass posting mode are not used; * methods from mail.message should not be available on survey composer; * most m2m fields coming from mail.message and composer have no use here; In this commit we simply add the required fields and template behavior on the survey composer and remove inheritance on mail.compose.message. This commit is linked to task ID 1909804 and PR #28783. --- .../wizard/survey_mail_compose_message.py | 83 +++++++++++++++++-- .../survey_mail_compose_message_views.xml | 4 - 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/addons/survey/wizard/survey_mail_compose_message.py b/addons/survey/wizard/survey_mail_compose_message.py index 1f1ab22a77e..fbc436457a4 100644 --- a/addons/survey/wizard/survey_mail_compose_message.py +++ b/addons/survey/wizard/survey_mail_compose_message.py @@ -5,6 +5,7 @@ import logging import re import uuid +from email.utils import formataddr from werkzeug import urls from odoo import api, fields, models, _ @@ -19,7 +20,6 @@ email_validator = re.compile(r"[^@]+@[^@]+\.[^@]+") class SurveyMailComposeMessage(models.TransientModel): _name = 'survey.mail.compose.message' - _inherit = 'mail.compose.message' _description = 'Email composition wizard for Survey' def default_survey_id(self): @@ -27,6 +27,38 @@ class SurveyMailComposeMessage(models.TransientModel): if context.get('model') == 'survey.survey': return context.get('res_id') + @api.model + def _get_default_from(self): + if self.env.user.email: + return formataddr((self.env.user.name, self.env.user.email)) + raise UserError(_("Unable to post message, please configure the sender's email address.")) + + @api.model + def _get_default_author(self): + return self.env.user.partner_id + + # composer content + subject = fields.Char('Subject') + body = fields.Html('Contents', default='', sanitize_style=True) + attachment_ids = fields.Many2many( + 'ir.attachment', 'survey_mail_compose_message_ir_attachments_rel', 'wizard_id', 'attachment_id', + string='Attachments') + template_id = fields.Many2one( + 'mail.template', 'Use template', index=True, + domain="[('model', '=', 'survey.survey')]") + # origin + email_from = fields.Char('From', default=_get_default_from, help="Email address of the sender.") + author_id = fields.Many2one( + 'res.partner', 'Author', index=True, + ondelete='set null', default=_get_default_author, + help="Author of the message.") + # recipients + partner_ids = fields.Many2many('res.partner', 'survey_mail_compose_message_res_partner_rel', 'wizard_id', 'partner_id', string='Existing contacts') + multi_email = fields.Text(string='List of emails', help="This list of emails of recipients will not be converted in contacts.\ + Emails must be separated by commas, semicolons or newline.") + # technical info + mail_server_id = fields.Many2one('ir.mail_server', 'Outgoing mail server') + # survey survey_id = fields.Many2one('survey.survey', string='Survey', default=default_survey_id, required=True) public = fields.Selection([('public_link', 'Share the public web link to your audience.'), ('email_public_link', 'Send by email the public web link to your audience.'), @@ -34,10 +66,6 @@ class SurveyMailComposeMessage(models.TransientModel): string='Share options', default='public_link', required=True) public_url = fields.Char(compute="_compute_survey_url", string="Public url") public_url_html = fields.Char(compute="_compute_survey_url", string="Public HTML web link") - partner_ids = fields.Many2many('res.partner', 'survey_mail_compose_message_res_partner_rel', 'wizard_id', 'partner_id', string='Existing contacts') - attachment_ids = fields.Many2many('ir.attachment', 'survey_mail_compose_message_ir_attachments_rel', 'wizard_id', 'attachment_id', string='Attachments') - multi_email = fields.Text(string='List of emails', help="This list of emails of recipients will not be converted in contacts.\ - Emails must be separated by commas, semicolons or newline.") date_deadline = fields.Date(string="Deadline to which the invitation to respond is valid", help="Deadline to which the invitation to respond for this survey is valid. If the field is empty,\ the invitation is still valid.") @@ -74,6 +102,49 @@ class SurveyMailComposeMessage(models.TransientModel): emails_checked.sort() self.multi_email = '\n'.join(emails_checked) + @api.onchange('template_id', 'survey_id') + def _onchange_template_id(self): + """ UPDATE ME """ + to_render_fields = [ + 'subject', 'body_html', + 'email_from', 'reply_to', + 'partner_to', 'email_to', 'email_cc', + 'attachment_ids', + 'mail_server_id' + ] + returned_fields = to_render_fields + ['partner_ids', 'attachments'] + for wizard in self: + if wizard.template_id: + values = {} + + template_values = wizard.template_id.generate_email([wizard.survey_id.id], fields=to_render_fields)[wizard.survey_id.id] + values = dict((field, template_values[field]) for field in returned_fields if template_values.get(field)) + values['body'] = values.pop('body_html', '') + + # transform attachments into attachment_ids; not attached to the document because this will + # be done further in the posting process, allowing to clean database if email not send + Attachment = self.env['ir.attachment'] + for attach_fname, attach_datas in values.pop('attachments', []): + data_attach = { + 'name': attach_fname, + 'datas': attach_datas, + 'datas_fname': attach_fname, + 'res_model': 'mail.compose.message', # TDE CHECKME + 'res_id': 0, + 'type': 'binary', # override default_type from context, possibly meant for another model! + } + values.setdefault('attachment_ids', list()).append(Attachment.create(data_attach).id) + else: + default_values = self.default_get(returned_fields) + values = dict((key, default_values[key]) for key in returned_fields if key in default_values) + + # This onchange should return command instead of ids for x2many field. + # ORM handle the assignation of command list on new onchange (api.v8), + # this force the complete replacement of x2many field with + # command and is compatible with onchange api.v7 + values = self._convert_to_write(values) + wizard.update(values) + #------------------------------------------------------ # Wizard validation and send #------------------------------------------------------ @@ -183,8 +254,6 @@ class SurveyMailComposeMessage(models.TransientModel): partner_list.append({'id': partner.id, 'email': partner.email}) if not len(emails_list) and not len(partner_list): - if wizard.model == 'res.partner' and wizard.res_id: - return False raise UserError(_("Please enter at least one valid recipient.")) for email in emails_list: diff --git a/addons/survey/wizard/survey_mail_compose_message_views.xml b/addons/survey/wizard/survey_mail_compose_message_views.xml index 167464896ba..515dbd4677a 100644 --- a/addons/survey/wizard/survey_mail_compose_message_views.xml +++ b/addons/survey/wizard/survey_mail_compose_message_views.xml @@ -10,10 +10,6 @@ survey.mail.compose.message
- - - - From cb59cb0436bf78fa643d7c6acc4ebaddc83bbb32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 26 Oct 2018 10:14:17 +0000 Subject: [PATCH 2/2] [REF] survey: rename invitation wizard to better match its business use Purpose is to have a somehow cleaner name for this wizard as its purpose is to send invitations. Email and composer are details on how it works. This commit is linked to task ID 1909804 and PR #28783. --- addons/survey/__manifest__.py | 2 +- addons/survey/models/survey_survey.py | 2 +- addons/survey/tests/test_survey.py | 8 ++++---- addons/survey/wizard/__init__.py | 2 +- .../{survey_mail_compose_message.py => survey_invite.py} | 8 ++++---- ...compose_message_views.xml => survey_invite_views.xml} | 9 +++------ 6 files changed, 14 insertions(+), 17 deletions(-) rename addons/survey/wizard/{survey_mail_compose_message.py => survey_invite.py} (98%) rename addons/survey/wizard/{survey_mail_compose_message_views.xml => survey_invite_views.xml} (93%) diff --git a/addons/survey/__manifest__.py b/addons/survey/__manifest__.py index 2c2e45bf93d..042076f1f2e 100644 --- a/addons/survey/__manifest__.py +++ b/addons/survey/__manifest__.py @@ -31,7 +31,7 @@ sent mails with personal token for the invitation of the survey. 'views/survey_question_views.xml', 'views/survey_page_views.xml', 'views/survey_templates.xml', - 'wizard/survey_mail_compose_message_views.xml', + 'wizard/survey_invite_views.xml', ], 'demo': [ 'data/survey_demo_user.xml', diff --git a/addons/survey/models/survey_survey.py b/addons/survey/models/survey_survey.py index 65955df273e..b78f947aeef 100644 --- a/addons/survey/models/survey_survey.py +++ b/addons/survey/models/survey_survey.py @@ -302,7 +302,7 @@ class Survey(models.Model): 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'form', - 'res_model': 'survey.mail.compose.message', + 'res_model': 'survey.invite', 'target': 'new', 'context': local_context, } diff --git a/addons/survey/tests/test_survey.py b/addons/survey/tests/test_survey.py index 2b6d46b14ff..312a566e56a 100644 --- a/addons/survey/tests/test_survey.py +++ b/addons/survey/tests/test_survey.py @@ -132,7 +132,7 @@ class TestSurvey(TransactionCase): 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'form', - 'res_model': 'survey.mail.compose.message', + 'res_model': 'survey.invite', 'target': 'new', 'context': ctx, }) @@ -150,15 +150,15 @@ class TestSurvey(TransactionCase): def test_07_survey_email_message(self): # Case-1: Executing send_mail with correct data. partner = self.env['res.partner'].create({'name': 'Marie De Cock', 'email': 'marie.de.cock@gmail.com'}) - survey_mail_message = self.env['survey.mail.compose.message'].sudo(self.survey_manager).create({ + survey_mail_message = self.env['survey.invite'].sudo(self.survey_manager).create({ 'survey_id': self.survey1.id, 'public': 'email_public_link', 'body': '__URL__', 'partner_ids': [(4, partner.id)]}) survey_mail_message.send_mail() # Case-2: Executing send_mail with incorrect data. mail_messages = [ - self.env['survey.mail.compose.message'].sudo(self.survey_manager).create({ # Mail Message without __URL__ in body. + self.env['survey.invite'].sudo(self.survey_manager).create({ # Mail Message without __URL__ in body. 'survey_id': self.survey1.id, 'public': 'email_public_link'}), - self.env['survey.mail.compose.message'].sudo(self.survey_manager).create({ # Mail Message without recipents. + self.env['survey.invite'].sudo(self.survey_manager).create({ # Mail Message without recipents. 'survey_id': self.survey1.id, 'public': 'email_public_link', 'body': "__URL__"})] for message in mail_messages: self.assertRaises(UserError, message.send_mail) diff --git a/addons/survey/wizard/__init__.py b/addons/survey/wizard/__init__.py index 09c05c0941a..df860ddab0d 100644 --- a/addons/survey/wizard/__init__.py +++ b/addons/survey/wizard/__init__.py @@ -1,4 +1,4 @@ # -*- encoding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from . import survey_mail_compose_message +from . import survey_invite diff --git a/addons/survey/wizard/survey_mail_compose_message.py b/addons/survey/wizard/survey_invite.py similarity index 98% rename from addons/survey/wizard/survey_mail_compose_message.py rename to addons/survey/wizard/survey_invite.py index fbc436457a4..4f8f57276cb 100644 --- a/addons/survey/wizard/survey_mail_compose_message.py +++ b/addons/survey/wizard/survey_invite.py @@ -18,9 +18,9 @@ emails_split = re.compile(r"[;,\n\r]+") email_validator = re.compile(r"[^@]+@[^@]+\.[^@]+") -class SurveyMailComposeMessage(models.TransientModel): - _name = 'survey.mail.compose.message' - _description = 'Email composition wizard for Survey' +class SurveyInvite(models.TransientModel): + _name = 'survey.invite' + _description = 'Survey Invitation Wizard' def default_survey_id(self): context = self.env.context @@ -78,7 +78,7 @@ class SurveyMailComposeMessage(models.TransientModel): @api.model def default_get(self, fields): - res = super(SurveyMailComposeMessage, self).default_get(fields) + res = super(SurveyInvite, self).default_get(fields) context = self.env.context if context.get('active_model') == 'res.partner' and context.get('active_ids'): res.update({'partner_ids': context['active_ids']}) diff --git a/addons/survey/wizard/survey_mail_compose_message_views.xml b/addons/survey/wizard/survey_invite_views.xml similarity index 93% rename from addons/survey/wizard/survey_mail_compose_message_views.xml rename to addons/survey/wizard/survey_invite_views.xml index 515dbd4677a..942714e0f43 100644 --- a/addons/survey/wizard/survey_mail_compose_message_views.xml +++ b/addons/survey/wizard/survey_invite_views.xml @@ -1,13 +1,10 @@ - - - - - survey.mail.compose.message.form - survey.mail.compose.message + + survey.invite.view.form + survey.invite