diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py
index bd99cfaa5e6..33bf3c25af9 100644
--- a/addons/mail/models/mail_message.py
+++ b/addons/mail/models/mail_message.py
@@ -111,6 +111,8 @@ class Message(models.Model):
model = fields.Char('Related Document Model')
res_id = fields.Many2oneReference('Related Document ID', model_field='model')
record_name = fields.Char('Message Record Name') # display_name of the related document
+ record_alias_domain_id = fields.Many2one('mail.alias.domain', 'Alias Domain', ondelete='set null')
+ record_company_id = fields.Many2one('res.company', 'Company', ondelete='set null')
# characteristics
message_type = fields.Selection([
('email', 'Email'),
diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py
index e56c23f4578..2df2cc36a0e 100644
--- a/addons/mail/models/mail_thread.py
+++ b/addons/mail/models/mail_thread.py
@@ -2123,6 +2123,10 @@ class MailThread(models.AbstractModel):
'partner_ids': partner_ids,
})
# add default-like values afterwards, to avoid useless queries
+ if 'record_alias_domain_id' not in msg_values:
+ msg_values['record_alias_domain_id'] = self.sudo()._mail_get_alias_domains(default_company=self.env.company)[self.id].id
+ if 'record_company_id' not in msg_values:
+ msg_values['record_company_id'] = self._mail_get_companies(default=self.env.company)[self.id].id
if 'reply_to' not in msg_values:
msg_values['reply_to'] = self._notify_get_reply_to(default=email_from)[self.id]
@@ -2597,6 +2601,11 @@ class MailThread(models.AbstractModel):
}
msg_values.update(msg_kwargs)
# add default-like values afterwards, to avoid useless queries
+ if self:
+ if 'record_alias_domain_id' not in msg_values:
+ msg_values['record_alias_domain_id'] = self._mail_get_alias_domains(default_company=self.env.company)[self.id].id
+ if 'record_company_id' not in msg_values:
+ msg_values['record_company_id'] = self._mail_get_companies(default=self.env.company)[self.id].id
if 'reply_to' not in msg_values:
msg_values['reply_to'] = self._notify_get_reply_to(default=email_from)[self.id if self else False]
@@ -2689,6 +2698,8 @@ class MailThread(models.AbstractModel):
'email_from': email_from,
# document
'model': self._name,
+ 'record_alias_domain_id': False,
+ 'record_company_id': False,
'record_name': False,
# content
'attachment_ids': attachment_ids,
@@ -2826,6 +2837,8 @@ class MailThread(models.AbstractModel):
'model',
'parent_id',
'partner_ids',
+ 'record_alias_domain_id',
+ 'record_company_id',
'record_name',
'reply_to',
'reply_to_force_new',
diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py
index 95798f552c1..4d5061c7551 100644
--- a/addons/mail/wizard/mail_compose_message.py
+++ b/addons/mail/wizard/mail_compose_message.py
@@ -121,6 +121,12 @@ class MailComposer(models.TransientModel):
res_domain_user_id = fields.Many2one(
'res.users', string='Responsible',
help='Used as context used to evaluate composer domain')
+ record_alias_domain_id = fields.Many2one(
+ 'mail.alias.domain', 'Alias Domain',
+ compute='_compute_record_environment', readonly=False, store=True) # useful only in monorecord comment mode
+ record_company_id = fields.Many2one(
+ 'res.company', 'Company',
+ compute='_compute_record_environment', readonly=False, store=True) # useful only in monorecord comment mode
record_name = fields.Char(
'Record Name',
compute='_compute_record_name', readonly=False, store=True) # useful only in monorecord comment mode
@@ -387,6 +393,34 @@ class MailComposer(models.TransientModel):
elif not active_res_ids and self.env.context.get('active_id'):
composer.res_ids = f"{[self.env.context['active_id']]}"
+ @api.depends('composition_mode', 'model', 'res_domain', 'res_ids')
+ def _compute_record_environment(self):
+ """ In monorecord mode, fetch record company and the linked alias domain,
+ easing future processing notably at post and notification sending time.
+
+ In batch mode it makes no sense to compute a single company, it will be
+ dynamically generated. """
+ toreset = self.filtered(
+ lambda comp: (comp.record_company_id or comp.record_alias_domain_id) and comp.composition_batch
+ )
+ if toreset:
+ toreset.record_alias_domain_id = False
+ toreset.record_company_id = False
+
+ toupdate = self.filtered(
+ lambda comp: not comp.composition_batch
+ )
+ for composer in toupdate:
+ res_ids = composer._evaluate_res_ids()
+ if composer.model and len(res_ids) == 1:
+ record = self.env[composer.model].browse(res_ids)
+ composer.record_company_id = record._mail_get_companies(
+ default=self.env.company
+ )[record.id]
+ composer.record_alias_domain_id = record._mail_get_alias_domains(
+ default_company=self.env.company
+ )[record.id]
+
@api.depends('composition_mode', 'model', 'parent_id', 'res_domain', 'res_ids')
def _compute_record_name(self):
""" Computation is coming either from parent message, either from the
@@ -781,6 +815,8 @@ class MailComposer(models.TransientModel):
STA - 'email_add_signature',
STA - 'email_layout_xmlid',
DYN - 'force_email_lang', # notify parameter
+ STA - 'record_alias_domain_id', # monorecord only
+ STA - 'record_company_id', # monorecord only
BOTH
DYN - 'attachment_ids',
@@ -879,6 +915,8 @@ class MailComposer(models.TransientModel):
force_send=self.force_send,
mail_auto_delete=self.auto_delete,
model_description=model_description,
+ record_alias_domain_id=self.record_alias_domain_id.id,
+ record_company_id=self.record_company_id.id,
)
return values
@@ -899,6 +937,10 @@ class MailComposer(models.TransientModel):
RecordsModel = self.env[self.model].with_prefetch(res_ids)
email_mode = self.composition_mode == 'mass_mail'
+ # records values
+ companies = RecordsModel.browse(res_ids)._mail_get_companies(default=self.env.company)
+ alias_domains = RecordsModel.browse(res_ids)._mail_get_alias_domains(default_company=self.env.company)
+
# langs, used currently only to propagate in comment mode for notification
# layout translation
langs = self._render_field('lang', res_ids)
@@ -916,6 +958,9 @@ class MailComposer(models.TransientModel):
'email_from': emails_from[res_id],
'scheduled_date': False,
'subject': subjects[res_id],
+ # record-specific environment values (company, alias_domain)
+ 'record_alias_domain_id': alias_domains[res_id].id,
+ 'record_company_id': companies[res_id].id,
# some fields are specific to mail
**(
{
diff --git a/addons/mail/wizard/mail_compose_message_views.xml b/addons/mail/wizard/mail_compose_message_views.xml
index 7d59093065f..3370d02acf7 100644
--- a/addons/mail/wizard/mail_compose_message_views.xml
+++ b/addons/mail/wizard/mail_compose_message_views.xml
@@ -21,6 +21,8 @@
+
+
diff --git a/addons/test_mail/tests/test_mail_composer.py b/addons/test_mail/tests/test_mail_composer.py
index 88769e7f0c8..3becd823fad 100644
--- a/addons/test_mail/tests/test_mail_composer.py
+++ b/addons/test_mail/tests/test_mail_composer.py
@@ -171,6 +171,8 @@ class TestComposerForm(TestMailComposer):
self.assertFalse(composer_form.mail_server_id)
self.assertEqual(composer_form.model, self.test_record._name)
self.assertFalse(composer_form.partner_ids)
+ self.assertEqual(composer_form.record_alias_domain_id, self.mail_alias_domain)
+ self.assertEqual(composer_form.record_company_id, self.env.company)
self.assertEqual(composer_form.record_name, self.test_record.name, 'MailComposer: comment mode should compute record name')
self.assertFalse(composer_form.reply_to)
self.assertFalse(composer_form.reply_to_force_new)
@@ -182,6 +184,32 @@ class TestComposerForm(TestMailComposer):
self.assertEqual(composer_form.subtype_id, self.env.ref('mail.mt_comment'))
self.assertFalse(composer_form.subtype_is_log)
+ @users('employee')
+ def test_mail_composer_comment_mc(self):
+ """ Test values specific to multi-company setup, in comment mode, using
+ the Form tool. """
+ # add access to second company to avoid MC rules on ticket model
+ self.env.user.company_ids = [(4, self.company_2.id)]
+ test_record = self.test_record.with_env(self.env)
+ source_company = [
+ self.company_admin,
+ self.company_2,
+ self.env['res.company'],
+ ]
+ expected = [
+ (self.company_admin, self.mail_alias_domain),
+ (self.company_2, self.mail_alias_domain_c2),
+ (self.company_admin, self.mail_alias_domain), # env company
+ ]
+ for company, (exp_company, exp_alias_domain) in zip(source_company, expected):
+ with self.subTest(cmopany=company):
+ test_record.write({'company_id': company.id})
+ composer_form = Form(self.env['mail.compose.message'].with_context(
+ self._get_web_context(self.test_record, add_web=True)
+ ))
+ self.assertEqual(composer_form.record_alias_domain_id, exp_alias_domain)
+ self.assertEqual(composer_form.record_company_id, exp_company)
+
@users('employee')
def test_mail_composer_comment_attachments(self):
"""Tests that all attachments are added to the composer, static attachments
@@ -251,6 +279,8 @@ class TestComposerForm(TestMailComposer):
self.assertEqual(composer_form.mail_server_id, self.mail_server_domain)
self.assertEqual(composer_form.model, self.test_record._name)
self.assertEqual(composer_form.partner_ids[:], self.partner_1)
+ self.assertEqual(composer_form.record_alias_domain_id, self.mail_alias_domain)
+ self.assertEqual(composer_form.record_company_id, self.env.company)
self.assertEqual(composer_form.record_name, self.test_record.name, 'MailComposer: comment mode should compute record name')
self.assertEqual(composer_form.reply_to, 'info@test.example.com')
self.assertFalse(composer_form.reply_to_force_new)
@@ -283,6 +313,8 @@ class TestComposerForm(TestMailComposer):
self.assertFalse(composer_form.force_send, 'MailComposer: batch record post use email queue for notifications')
self.assertEqual(composer_form.mail_server_id, self.mail_server_domain)
self.assertEqual(composer_form.model, self.test_record._name)
+ self.assertFalse(composer_form.record_alias_domain_id, 'MailComposer: comment in batch mode should have void alias domain')
+ self.assertFalse(composer_form.record_company_id, 'MailComposer: comment in batch mode should have void company')
self.assertFalse(composer_form.record_name, 'MailComposer: comment in batch mode should have void record name')
self.assertEqual(composer_form.reply_to, self.template.reply_to)
self.assertFalse(composer_form.reply_to_force_new)
@@ -315,6 +347,8 @@ class TestComposerForm(TestMailComposer):
self.assertFalse(composer_form.force_send, 'MailComposer: batch record post use email queue for notifications')
self.assertEqual(composer_form.mail_server_id, self.mail_server_domain)
self.assertEqual(composer_form.model, self.test_record._name)
+ self.assertFalse(composer_form.record_alias_domain_id, 'MailComposer: comment in batch mode should have void alias domain')
+ self.assertFalse(composer_form.record_company_id, 'MailComposer: comment in batch mode should have void company')
self.assertFalse(composer_form.record_name, 'MailComposer: comment in batch mode should have void record name')
self.assertEqual(composer_form.reply_to, self.template.reply_to)
self.assertFalse(composer_form.reply_to_force_new)
@@ -347,6 +381,8 @@ class TestComposerForm(TestMailComposer):
self.assertEqual(composer_form.mail_server_id, self.mail_server_domain)
self.assertEqual(composer_form.model, self.test_record._name)
self.assertFalse(composer_form.partner_ids[:])
+ self.assertFalse(composer_form.record_alias_domain_id)
+ self.assertFalse(composer_form.record_company_id)
self.assertFalse(composer_form.record_name)
self.assertEqual(composer_form.reply_to, 'info@test.example.com')
self.assertFalse(composer_form.reply_to_force_new)
@@ -375,6 +411,8 @@ class TestComposerForm(TestMailComposer):
self.assertTrue(composer_form.force_send, 'MailComposer: mass mode sends emails right away')
self.assertFalse(composer_form.mail_server_id)
self.assertEqual(composer_form.model, self.test_records._name)
+ self.assertFalse(composer_form.record_alias_domain_id, 'MailComposer: mass mode should have void alias domain')
+ self.assertFalse(composer_form.record_company_id, 'MailComposer: mass mode should have void company')
self.assertFalse(composer_form.record_name, 'MailComposer: mass mode should have void record name')
self.assertFalse(composer_form.reply_to)
self.assertFalse(composer_form.reply_to_force_new)
@@ -404,6 +442,8 @@ class TestComposerForm(TestMailComposer):
self.assertTrue(composer_form.force_send, 'MailComposer: mass mode sends emails right away')
self.assertEqual(composer_form.mail_server_id, self.mail_server_domain)
self.assertEqual(composer_form.model, self.test_records._name)
+ self.assertFalse(composer_form.record_alias_domain_id, 'MailComposer: mass mode should have void alias domain')
+ self.assertFalse(composer_form.record_company_id, 'MailComposer: mass mode should have void company')
self.assertFalse(composer_form.record_name, 'MailComposer: mass mode should have void record name')
self.assertEqual(composer_form.reply_to, self.template.reply_to)
self.assertFalse(composer_form.reply_to_force_new)
@@ -437,6 +477,8 @@ class TestComposerForm(TestMailComposer):
self.assertTrue(composer_form.force_send, 'MailComposer: mass mode sends emails right away')
self.assertEqual(composer_form.mail_server_id, self.mail_server_domain)
self.assertEqual(composer_form.model, self.test_records._name)
+ self.assertFalse(composer_form.record_alias_domain_id, 'MailComposer: mass mode should have void alias domain')
+ self.assertFalse(composer_form.record_company_id, 'MailComposer: mass mode should have void company')
self.assertFalse(composer_form.record_name, 'MailComposer: mass mode should have void record name')
self.assertEqual(composer_form.reply_to, self.template.reply_to)
self.assertFalse(composer_form.reply_to_force_new)
@@ -470,6 +512,8 @@ class TestComposerForm(TestMailComposer):
self.assertTrue(composer_form.force_send, 'MailComposer: mass mode sends emails right away')
self.assertEqual(composer_form.mail_server_id, self.mail_server_domain)
self.assertEqual(composer_form.model, self.test_records._name)
+ self.assertFalse(composer_form.record_alias_domain_id, 'MailComposer: mass mode should have void alias domain')
+ self.assertFalse(composer_form.record_company_id, 'MailComposer: mass mode should have void company')
self.assertFalse(composer_form.record_name, 'MailComposer: mass mode should have void record name')
self.assertEqual(composer_form.reply_to, self.template.reply_to)
self.assertFalse(composer_form.reply_to_force_new)
@@ -1262,6 +1306,12 @@ class TestComposerResultsComment(TestMailComposer, CronMixinCase):
""" Ensure class initial data to ease understanding """
self.assertTrue(self.template.auto_delete)
+ self.assertEqual(len(self.test_record), 1)
+ self.assertEqual(self.test_record.user_id, self.user_employee_2)
+ self.assertEqual(self.test_record.message_partner_ids, self.partner_employee_2)
+ self.assertEqual(self.test_record[0].customer_id.lang, 'en_US')
+ self.assertEqual(self.test_record.company_id, self.company_admin)
+
self.assertEqual(len(self.test_records), 2)
self.assertEqual(self.test_records.user_id, self.user_employee_2)
self.assertEqual(self.test_records.message_partner_ids, self.partner_employee_2)
@@ -1844,7 +1894,6 @@ class TestComposerResultsComment(TestMailComposer, CronMixinCase):
self.assertEqual(set(message.attachment_ids.mapped('res_id')), set(test_record.ids))
self.assertTrue(all(attach not in message.attachment_ids for attach in attachs), 'Should have copied attachments')
-
@users('employee')
@mute_logger('odoo.addons.mail.models.mail_mail')
def test_mail_composer_wtpl_mc(self):
@@ -1871,11 +1920,11 @@ class TestComposerResultsComment(TestMailComposer, CronMixinCase):
attachs = self.env['ir.attachment'].search([('name', 'in', [a['name'] for a in attachment_data])])
self.assertEqual(len(attachs), 2)
- for batch, companies, expected_companies in [
+ for batch, companies, expected_companies, expected_alias_domains in [
+ (False, self.company_admin, self.company_admin, self.mail_alias_domain),
(
- False, self.company_admin, self.company_admin
- ), (
True, self.company_admin + self.company_2, self.company_admin + self.company_2,
+ self.mail_alias_domain + self.mail_alias_domain_c2,
),
]:
with self.subTest(batch=batch,
@@ -1902,8 +1951,8 @@ class TestComposerResultsComment(TestMailComposer, CronMixinCase):
new_partner = self.env['res.partner'].search([('email_normalized', '=', 'test.to.1@test.example.com')])
self.assertEqual(len(new_partner), 1)
# check output, company-specific values mainly for this test
- for record, exp_company in zip(
- test_records, expected_companies
+ for record, exp_company, exp_alias_domain in zip(
+ test_records, expected_companies, expected_alias_domains
):
message = record.message_ids[0]
for recipient in [self.partner_employee_2, new_partner, record.customer_id]:
@@ -1924,6 +1973,8 @@ class TestComposerResultsComment(TestMailComposer, CronMixinCase):
'X-Odoo-Objects': f'{record._name}-{record.id}',
},
'mail_server_id': self.env['ir.mail_server'],
+ 'record_alias_domain_id': exp_alias_domain,
+ 'record_company_id': exp_company,
'subject': f'TemplateSubject {record.name}',
},
)