summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
Diffstat (limited to 'addons')
-rw-r--r--addons/account/models/account_move.py10
-rw-r--r--addons/hr/models/__init__.py1
-rw-r--r--addons/hr/models/mail_alias.py21
-rw-r--r--addons/hr/models/models.py20
-rw-r--r--addons/mail/models/mail_alias_mixin.py21
-rw-r--r--addons/mail/models/mail_channel.py4
-rw-r--r--addons/mail/models/mail_message.py6
-rw-r--r--addons/mail/models/mail_template.py2
-rw-r--r--addons/mail/models/mail_thread.py159
-rw-r--r--addons/mail/models/models.py170
-rw-r--r--addons/mail/wizard/mail_compose_message.py4
11 files changed, 220 insertions, 198 deletions
diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py
index 99f6195d4f6..7bfff747fdd 100644
--- a/addons/account/models/account_move.py
+++ b/addons/account/models/account_move.py
@@ -3713,16 +3713,16 @@ class AccountMoveLine(models.Model):
for move_id, modified_lines in move_initial_values.items():
tmp_move = {move_id: []}
for line in self.filtered(lambda l: l.move_id.id == move_id):
- tracked_field = self.env['mail.thread'].static_message_track(line, ref_fields, modified_lines) # Return a tuple like (changed field, ORM command)
+ changes, tracking_value_ids = line._mail_track(ref_fields, modified_lines) # Return a tuple like (changed field, ORM command)
tmp = {'line_id': line.id}
- if len(tracked_field[1]) > 0:
- selected_field = tracked_field[1][0][2] # Get the last element of the tuple in the list of ORM command. (changed, [(0, 0, THIS)])
+ if tracking_value_ids:
+ selected_field = tracking_value_ids[0][2] # Get the last element of the tuple in the list of ORM command. (changed, [(0, 0, THIS)])
tmp.update({
**{'field_name': selected_field.get('field_desc')},
**self._get_formated_values(selected_field)
})
- elif len(tracked_field[0]):
- field_name = line._fields[tracked_field[0].pop()].string # Get the field name
+ elif changes:
+ field_name = line._fields[changes.pop()].string # Get the field name
tmp.update({
'error': True,
'field_error': field_name
diff --git a/addons/hr/models/__init__.py b/addons/hr/models/__init__.py
index 1c06c535ae8..f9e64bc7013 100644
--- a/addons/hr/models/__init__.py
+++ b/addons/hr/models/__init__.py
@@ -10,6 +10,7 @@ from . import hr_job
from . import hr_plan
from . import mail_alias
from . import mail_channel
+from . import models
from . import res_config_settings
from . import res_partner
from . import res_users
diff --git a/addons/hr/models/mail_alias.py b/addons/hr/models/mail_alias.py
index 3d652142f68..69042cfb1bd 100644
--- a/addons/hr/models/mail_alias.py
+++ b/addons/hr/models/mail_alias.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo import fields, models, tools, _
+from odoo import fields, models, _
class Alias(models.Model):
@@ -16,21 +16,4 @@ class Alias(models.Model):
return _("""Hi,<br/>
Your document has not been created because your email address is not recognized.<br/>
Please send emails with the email address recorded on your employee information, or contact your HR manager.""")
- else:
- return super(Alias, self)._get_alias_bounced_body_fallback(message_dict)
-
-
-class AliasMixin(models.AbstractModel):
- _inherit = 'mail.alias.mixin'
-
- def _alias_check_contact_on_record(self, record, message, message_dict, alias):
- if alias.alias_contact == 'employees':
- email_from = tools.decode_message_header(message, 'From')
- email_address = tools.email_split(email_from)[0]
- employee = self.env['hr.employee'].search([('work_email', 'ilike', email_address)], limit=1)
- if not employee:
- employee = self.env['hr.employee'].search([('user_id.email', 'ilike', email_address)], limit=1)
- if not employee:
- return _('restricted to employees')
- return True
- return super(AliasMixin, self)._alias_check_contact_on_record(record, message, message_dict, alias)
+ return super(Alias, self)._get_alias_bounced_body_fallback(message_dict)
diff --git a/addons/hr/models/models.py b/addons/hr/models/models.py
new file mode 100644
index 00000000000..dd615798364
--- /dev/null
+++ b/addons/hr/models/models.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models, tools, _
+
+
+class BaseModel(models.AbstractModel):
+ _inherit = 'base'
+
+ def _alias_get_error_message(self, message, message_dict, alias):
+ if alias.alias_contact == 'employees':
+ email_from = tools.decode_message_header(message, 'From')
+ email_address = tools.email_split(email_from)[0]
+ employee = self.env['hr.employee'].search([('work_email', 'ilike', email_address)], limit=1)
+ if not employee:
+ employee = self.env['hr.employee'].search([('user_id.email', 'ilike', email_address)], limit=1)
+ if not employee:
+ return _('restricted to employees')
+ return True
+ return super(BaseModel, self)._alias_get_error_message(message, message_dict, alias)
diff --git a/addons/mail/models/mail_alias_mixin.py b/addons/mail/models/mail_alias_mixin.py
index f753136669f..b06cd174a71 100644
--- a/addons/mail/models/mail_alias_mixin.py
+++ b/addons/mail/models/mail_alias_mixin.py
@@ -125,23 +125,6 @@ class AliasMixin(models.AbstractModel):
# GATEWAY
# --------------------------------------------------
- def _alias_check_contact(self, message, message_dict, alias):
- """ Main mixin method that inheriting models may inherit in order
- to implement a specifc behavior. """
- return self._alias_check_contact_on_record(self, message, message_dict, alias)
-
def _alias_check_contact_on_record(self, record, message, message_dict, alias):
- """ Generic method that takes a record not necessarily inheriting from
- mail.alias.mixin. """
- author = self.env['res.partner'].browse(message_dict.get('author_id', False))
- if alias.alias_contact == 'followers':
- if not record.ids:
- return _('incorrectly configured alias (unknown reference record)')
- if not hasattr(record, "message_partner_ids") or not hasattr(record, "message_channel_ids"):
- return _('incorrectly configured alias')
- accepted_partner_ids = record.message_partner_ids | record.message_channel_ids.mapped('channel_partner_ids')
- if not author or author not in accepted_partner_ids:
- return _('restricted to followers')
- elif alias.alias_contact == 'partners' and not author:
- return _('restricted to known authors')
- return True
+ """ Move to ``BaseModel._alias_get_error_message() """
+ return record._alias_get_error_message(message, message_dict, alias)
diff --git a/addons/mail/models/mail_channel.py b/addons/mail/models/mail_channel.py
index 093c94878b4..d63b1ecf80b 100644
--- a/addons/mail/models/mail_channel.py
+++ b/addons/mail/models/mail_channel.py
@@ -386,13 +386,13 @@ class Channel(models.Model):
})
return message
- def _alias_check_contact(self, message, message_dict, alias):
+ def _alias_get_error_message(self, message, message_dict, alias):
if alias.alias_contact == 'followers' and self.ids:
author = self.env['res.partner'].browse(message_dict.get('author_id', False))
if not author or author not in self.channel_partner_ids:
return _('restricted to channel members')
return True
- return super(Channel, self)._alias_check_contact(message, message_dict, alias)
+ return super(Channel, self)._alias_get_error_message(message, message_dict, alias)
def init(self):
self._cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = %s', ('mail_channel_partner_seen_message_id_idx',))
diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py
index f74596c1226..84b0976ed3e 100644
--- a/addons/mail/models/mail_message.py
+++ b/addons/mail/models/mail_message.py
@@ -1167,15 +1167,15 @@ class Message(models.Model):
def _get_reply_to(self, values):
""" Return a specific reply_to for the document """
model = values.get('model', self._context.get('default_model'))
- res_id = values.get('res_id', self._context.get('default_res_id'))
+ res_id = values.get('res_id', self._context.get('default_res_id')) or False
email_from = values.get('email_from')
message_type = values.get('message_type')
records = None
if self.is_thread_message({'model': model, 'res_id': res_id, 'message_type': message_type}):
records = self.env[model].browse([res_id])
else:
- res_id = False
- return self.env['mail.thread']._notify_get_reply_to_on_records(default=email_from, records=records)[res_id]
+ records = self.env[model] if model else self.env['mail.thread']
+ return records._notify_get_reply_to(default=email_from)[res_id]
@api.model
def _get_message_id(self, values):
diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py
index 92783104b65..e0d3c30490e 100644
--- a/addons/mail/models/mail_template.py
+++ b/addons/mail/models/mail_template.py
@@ -116,7 +116,7 @@ class MailTemplate(models.Model):
if self.use_default_to or self._context.get('tpl_force_default_to'):
records = self.env[self.model].browse(res_ids).sudo()
- default_recipients = self.env['mail.thread']._message_get_default_recipients_on_records(records)
+ default_recipients = records._message_get_default_recipients()
for res_id, recipients in default_recipients.items():
results[res_id].pop('partner_to', None)
results[res_id].update(recipients)
diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py
index 22497352bec..3a9c68db2a9 100644
--- a/addons/mail/models/mail_thread.py
+++ b/addons/mail/models/mail_thread.py
@@ -583,38 +583,6 @@ class MailThread(models.AbstractModel):
def _track_template(self, changes):
return dict()
- @api.model
- def static_message_track(self, record, tracked_fields, initial):
- """ For a given record, fields to check (tuple column name, column info)
- and initial values, return a structure that is a tuple containing :
- - a set of updated column names
- - a list of ORM (0, 0, values) commands to create 'mail.tracking.value'
- This static method is usefull when you don't want to inherit from mail.thread but
- you want to use '_message_track()' method.
- """
- record.ensure_one()
- changes = set() # contains onchange tracked fields that changed
- tracking_value_ids = []
-
- # generate tracked_values data structure: {'col_name': {col_info, new_value, old_value}}
- for col_name, col_info in tracked_fields.items():
- if col_name not in initial:
- continue
- initial_value = initial[col_name]
- new_value = record[col_name]
-
- if new_value != initial_value and (new_value or initial_value): # because browse null != False
- tracking_sequence = getattr(record._fields[col_name], 'tracking',
- getattr(record._fields[col_name], 'track_sequence', 100)) # backward compatibility with old parameter name
- if tracking_sequence is True:
- tracking_sequence = 100
- tracking = record.env['mail.tracking.value'].create_tracking_values(initial_value, new_value, col_name, col_info, tracking_sequence, record._name)
- if tracking:
- tracking_value_ids.append([0, 0, tracking])
- changes.add(col_name)
-
- return changes, tracking_value_ids
-
def message_track(self, tracked_fields, initial_values):
""" Track updated values. Comparing the initial and current values of
the fields given in tracked_fields, it generates a message containing
@@ -657,12 +625,13 @@ class MailThread(models.AbstractModel):
return tracking
+ def static_message_track(self, record, tracked_fields, initial):
+ """ Deprecated, remove in v14+ """
+ return record._mail_track(tracked_fields, initial)
+
def _message_track(self, tracked_fields, initial):
- """ For a given record, fields to check (tuple column name, column info)
- and initial values, return a structure that is a tuple containing :
- - a set of updated column names
- - a list of ORM (0, 0, values) commands to create 'mail.tracking.value' """
- return self.static_message_track(self, tracked_fields, initial)
+ """ Moved to ``BaseModel._mail_track()`` """
+ return self._mail_track(tracked_fields, initial)
def _track_subtype(self, init_values):
""" Give the subtypes triggered by the changes on the record according
@@ -844,13 +813,10 @@ class MailThread(models.AbstractModel):
obj = self.env[alias.alias_parent_model_id.model].browse(alias.alias_parent_thread_id)
else:
obj = self.env[model]
- if hasattr(obj, '_alias_check_contact'):
- error_code = obj._alias_check_contact(message, message_dict, alias)
- else:
- error_code = self.env['mail.alias.mixin']._alias_check_contact_on_record(obj, message, message_dict, alias)
- if error_code is not True:
+ error_message = obj._alias_get_error_message(message, message_dict, alias)
+ if error_message:
self._routing_warn(
- _('alias %(name)s: %(error)s', name=alias.alias_name, error=error_code or _('unknown error')),
+ _('alias %(name)s: %(error)s', name=alias.alias_name, error=error_message or _('unknown error')),
message_id,
route,
False
@@ -1491,27 +1457,8 @@ class MailThread(models.AbstractModel):
@api.model
def _message_get_default_recipients_on_records(self, records):
- """ Generic implementation for finding default recipient to mail on
- a recordset. ``_message_get_default_recipients`` may be defined to
- implement custom behavior. """
- if hasattr(records, '_message_get_default_recipients'):
- return records._message_get_default_recipients()
-
- res = {}
- for record in records:
- recipient_ids, email_to, email_cc = [], False, False
- if 'partner_id' in record and record.partner_id:
- recipient_ids.append(record.partner_id.id)
- elif 'email_normalized' in record and record.email_normalized:
- email_to = record.email_normalized
- elif 'email_from' in record and record.email_from:
- email_to = record.email_from
- elif 'partner_email' in record and record.partner_email:
- email_to = record.partner_email
- elif 'email' in record and record.email:
- email_to = record.email
- res[record.id] = {'partner_ids': recipient_ids, 'email_to': email_to, 'email_cc': email_cc}
- return res
+ """ Moved to ``BaseModel._message_get_default_recipients()`` """
+ return records._message_get_default_recipients()
def _message_add_suggested_recipient(self, result, partner=None, email=None, reason=''):
""" Called by _message_get_suggested_recipients, to add a suggested
@@ -2646,89 +2593,11 @@ class MailThread(models.AbstractModel):
return result
- def _notify_get_reply_to(self, default=None, records=None, company=None, doc_names=None):
- """ Returns the preferred reply-to email address when replying to a thread
- on documents. Documents are either given by self it this method is called
- as a true multi method on a record set or can be given using records to
- have a generic implementation available for all models.
- Reply-to is formatted like "MyCompany MyDocument <reply.to@domain>".
- Heuristic it the following:
- * search for specific aliases as they always have priority; it is limited
- to aliases linked to documents (like project alias for task for example);
- * use catchall address;
- * use default;
- This method works on documents
- * as a true multi method for models inheriting from mail.thread; call
- ``records._notify_get_reply_to(...)``;
- * as a generic implementation if records are given; call ``MailThread.
- _notify_get_reply_to(records=records, ...)``;
- * as a generic implementation is self is a void mail.thread record set
- meaning catchall is computed; call ``MailThread._notify_get_reply_to
- (records=None)``;
- Tweak this method on a specific model by overriding if it inherits from
- mail.thread. An example would be tasks taking their reply-to alias from
- their project.
- :param default: default email if no alias or catchall is found;
- :param records: record_set if self if a generic mail.thread record allowing
- generic implementation of finding reply-to;
- :param company: used to compute company name part of the from name; provide
- it if already known, otherwise fall back on user company;
- :param doc_names: dict(res_id, doc_name) used to compute doc name part of
- the from name; provide it if already known to avoid queries, otherwise
- name_get on document will be performed;
- :return result: dictionary. Keys are record IDs and value is formatted
- like an email "Company_name Document_name <reply_to@email>"/
- """
- _records = self if self and self._name != 'mail.thread' else records
- model = _records._name if _records and _records._name != 'mail.thread' else False
- res_ids = _records.ids if _records and model else []
- _res_ids = res_ids or [False] # always have a default value located in False
-
- alias_domain = self.env['ir.config_parameter'].sudo().get_param("mail.catchall.domain")
- result = dict.fromkeys(_res_ids, False)
- result_email = dict()
- doc_names = doc_names if doc_names else dict()
-
- if alias_domain:
- if model and res_ids:
- if not doc_names:
- doc_names = dict((rec.id, rec.display_name) for rec in _records)
-
- mail_aliases = self.env['mail.alias'].sudo().search([
- ('alias_parent_model_id.model', '=', model),
- ('alias_parent_thread_id', 'in', res_ids),
- ('alias_name', '!=', False)])
- # take only first found alias for each thread_id, to match order (1 found -> limit=1 for each res_id)
- for alias in mail_aliases:
- result_email.setdefault(alias.alias_parent_thread_id, '%s@%s' % (alias.alias_name, alias_domain))
-
- # left ids: use catchall
- left_ids = set(_res_ids) - set(result_email)
- if left_ids:
- catchall = self.env['ir.config_parameter'].sudo().get_param("mail.catchall.alias")
- if catchall:
- result_email.update(dict((rid, '%s@%s' % (catchall, alias_domain)) for rid in left_ids))
-
- # compute name of reply-to - TDE tocheck: quotes and stuff like that
- company_name = company.name if company else self.env.company.name
- for res_id in result_email.keys():
- name = '%s%s%s' % (company_name, ' ' if doc_names.get(res_id) else '', doc_names.get(res_id, ''))
- result[res_id] = tools.formataddr((name, result_email[res_id]))
-
- left_ids = set(_res_ids) - set(result_email)
- if left_ids:
- result.update(dict((res_id, default) for res_id in left_ids))
-
- return result
-
@api.model
def _notify_get_reply_to_on_records(self, default=None, records=None, company=None, doc_names=None):
- """ Generic wrapper on ``_notify_get_reply_to`` checking mail.thread inheritance
- and allowing to call model-specific implementation in a one liner. This
- method should not be overridden. """
- if records and hasattr(records, '_notify_get_reply_to'):
- return records._notify_get_reply_to(default=default, company=company, doc_names=doc_names)
- return self._notify_get_reply_to(default=default, records=records, company=company, doc_names=doc_names)
+ """ Moved to ``BaseModel._notify_get_reply_to()`` """
+ records = records if records else self
+ return records._notify_get_reply_to(default=default, company=company, doc_names=doc_names)
def _notify_email_recipient_values(self, recipient_ids):
""" Format email notification recipient values to store on the notification
diff --git a/addons/mail/models/models.py b/addons/mail/models/models.py
index 1159a7ff6fd..1008fe0c4bf 100644
--- a/addons/mail/models/models.py
+++ b/addons/mail/models/models.py
@@ -3,15 +3,181 @@
from lxml.builder import E
-from odoo import models, api
+from odoo import api, models, tools, _
class BaseModel(models.AbstractModel):
_inherit = 'base'
# ------------------------------------------------------------
+ # GENERIC MAIL FEATURES
+ # ------------------------------------------------------------
+
+ def _mail_track(self, tracked_fields, initial):
+ """ For a given record, fields to check (tuple column name, column info)
+ and initial values, return a valid command to create tracking values.
+
+ :param tracked_fields: fields_get of updated fields on which tracking
+ is checked and performed;
+ :param initial: dict of initial values for each updated fields;
+
+ :return: a tuple (changes, tracking_value_ids) where
+ changes: set of updated column names;
+ tracking_value_ids: a list of ORM (0, 0, values) commands to create
+ ``mail.tracking.value`` records;
+
+ Override this method on a specific model to implement model-specific
+ behavior. Also consider inheriting from ``mail.thread``. """
+ self.ensure_one()
+ changes = set() # contains onchange tracked fields that changed
+ tracking_value_ids = []
+
+ # generate tracked_values data structure: {'col_name': {col_info, new_value, old_value}}
+ for col_name, col_info in tracked_fields.items():
+ if col_name not in initial:
+ continue
+ initial_value = initial[col_name]
+ new_value = self[col_name]
+
+ if new_value != initial_value and (new_value or initial_value): # because browse null != False
+ tracking_sequence = getattr(self._fields[col_name], 'tracking',
+ getattr(self._fields[col_name], 'track_sequence', 100)) # backward compatibility with old parameter name
+ if tracking_sequence is True:
+ tracking_sequence = 100
+ tracking = self.env['mail.tracking.value'].create_tracking_values(initial_value, new_value, col_name, col_info, tracking_sequence, self._name)
+ if tracking:
+ tracking_value_ids.append([0, 0, tracking])
+ changes.add(col_name)
+
+ return changes, tracking_value_ids
+
+ def _message_get_default_recipients(self):
+ """ Generic implementation for finding default recipient to mail on
+ a recordset. This method is a generic implementation available for
+ all models as we could send an email through mail templates on models
+ not inheriting from mail.thread.
+
+ Override this method on a specific model to implement model-specific
+ behavior. Also consider inheriting from ``mail.thread``. """
+ res = {}
+ for record in self:
+ recipient_ids, email_to, email_cc = [], False, False
+ if 'partner_id' in record and record.partner_id:
+ recipient_ids.append(record.partner_id.id)
+ elif 'email_normalized' in record and record.email_normalized:
+ email_to = record.email_normalized
+ elif 'email_from' in record and record.email_from:
+ email_to = record.email_from
+ elif 'partner_email' in record and record.partner_email:
+ email_to = record.partner_email
+ elif 'email' in record and record.email:
+ email_to = record.email
+ res[record.id] = {'partner_ids': recipient_ids, 'email_to': email_to, 'email_cc': email_cc}
+ return res
+
+ def _notify_get_reply_to(self, default=None, records=None, company=None, doc_names=None):
+ """ Returns the preferred reply-to email address when replying to a thread
+ on documents. This method is a generic implementation available for
+ all models as we could send an email through mail templates on models
+ not inheriting from mail.thread.
+
+ Reply-to is formatted like "MyCompany MyDocument <reply.to@domain>".
+ Heuristic it the following:
+ * search for specific aliases as they always have priority; it is limited
+ to aliases linked to documents (like project alias for task for example);
+ * use catchall address;
+ * use default;
+
+ This method can be used as a generic tools if self is a void recordset.
+
+ Override this method on a specific model to implement model-specific
+ behavior. Also consider inheriting from ``mail.thread``.
+ An example would be tasks taking their reply-to alias from their project.
+
+ :param default: default email if no alias or catchall is found;
+ :param records: DEPRECATED, self should be a valid record set or an
+ empty recordset if a generic reply-to is required;
+ :param company: used to compute company name part of the from name; provide
+ it if already known, otherwise fall back on user company;
+ :param doc_names: dict(res_id, doc_name) used to compute doc name part of
+ the from name; provide it if already known to avoid queries, otherwise
+ name_get on document will be performed;
+ :return result: dictionary. Keys are record IDs and value is formatted
+ like an email "Company_name Document_name <reply_to@email>"/
+ """
+ if records:
+ raise ValueError('Use of records is deprecated as this method is available on BaseModel.')
+
+ _records = self
+ model = _records._name if _records and _records._name != 'mail.thread' else False
+ res_ids = _records.ids if _records and model else []
+ _res_ids = res_ids or [False] # always have a default value located in False
+
+ alias_domain = self.env['ir.config_parameter'].sudo().get_param("mail.catchall.domain")
+ result = dict.fromkeys(_res_ids, False)
+ result_email = dict()
+ doc_names = doc_names if doc_names else dict()
+
+ if alias_domain:
+ if model and res_ids:
+ if not doc_names:
+ doc_names = dict((rec.id, rec.display_name) for rec in _records)
+
+ mail_aliases = self.env['mail.alias'].sudo().search([
+ ('alias_parent_model_id.model', '=', model),
+ ('alias_parent_thread_id', 'in', res_ids),
+ ('alias_name', '!=', False)])
+ # take only first found alias for each thread_id, to match order (1 found -> limit=1 for each res_id)
+ for alias in mail_aliases:
+ result_email.setdefault(alias.alias_parent_thread_id, '%s@%s' % (alias.alias_name, alias_domain))
+
+ # left ids: use catchall
+ left_ids = set(_res_ids) - set(result_email)
+ if left_ids:
+ catchall = self.env['ir.config_parameter'].sudo().get_param("mail.catchall.alias")
+ if catchall:
+ result_email.update(dict((rid, '%s@%s' % (catchall, alias_domain)) for rid in left_ids))
+
+ # compute name of reply-to - TDE tocheck: quotes and stuff like that
+ company_name = company.name if company else self.env.company.name
+ for res_id in result_email:
+ name = '%s%s%s' % (company_name, ' ' if doc_names.get(res_id) else '', doc_names.get(res_id, ''))
+ result[res_id] = tools.formataddr((name, result_email[res_id]))
+
+ left_ids = set(_res_ids) - set(result_email)
+ if left_ids:
+ result.update(dict((res_id, default) for res_id in left_ids))
+
+ return result
+
+ # ------------------------------------------------------------
+ # ALIAS MANAGEMENT
+ # ------------------------------------------------------------
+
+ def _alias_check_contact(self, message, message_dict, alias):
+ """ Deprecated, remove in v14+ """
+ error_msg = self._alias_get_error_message(message, message_dict, alias)
+ return error_msg if error_msg else True
+
+ def _alias_get_error_message(self, message, message_dict, alias):
+ """ Generic method that takes a record not necessarily inheriting from
+ mail.alias.mixin. """
+ author = self.env['res.partner'].browse(message_dict.get('author_id', False))
+ if alias.alias_contact == 'followers':
+ if not self.ids:
+ return _('incorrectly configured alias (unknown reference record)')
+ if not hasattr(self, "message_partner_ids") or not hasattr(self, "message_channel_ids"):
+ return _('incorrectly configured alias')
+ accepted_partner_ids = self.message_partner_ids | self.message_channel_ids.mapped('channel_partner_ids')
+ if not author or author not in accepted_partner_ids:
+ return _('restricted to followers')
+ elif alias.alias_contact == 'partners' and not author:
+ return _('restricted to known authors')
+ return False
+
+ # ------------------------------------------------------------
# ACTIVITY
- # -----------------------------------------------------------
+ # ------------------------------------------------------------
@api.model
def _get_default_activity_view(self):
diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py
index f66bdba6557..e9df4a0cb80 100644
--- a/addons/mail/wizard/mail_compose_message.py
+++ b/addons/mail/wizard/mail_compose_message.py
@@ -278,7 +278,7 @@ class MailComposer(models.TransientModel):
reply_to_value = dict.fromkeys(res_ids, None)
if mass_mail_mode and not self.no_auto_thread:
records = self.env[self.model].browse(res_ids)
- reply_to_value = self.env['mail.thread']._notify_get_reply_to_on_records(default=self.email_from, records=records)
+ reply_to_value = records._notify_get_reply_to(default=self.email_from)
blacklisted_rec_ids = []
if mass_mail_mode and issubclass(type(self.env[self.model]), self.pool['mail.thread.blacklist']):
@@ -462,7 +462,7 @@ class MailComposer(models.TransientModel):
default_recipients = {}
if not self.partner_ids:
records = self.env[self.model].browse(res_ids).sudo()
- default_recipients = self.env['mail.thread']._message_get_default_recipients_on_records(records)
+ default_recipients = records._message_get_default_recipients()
results = dict.fromkeys(res_ids, False)
for res_id in res_ids: