[REF] mail: move generic methods from thread to BaseModel
PURPOSE
Since v13 some commits added code in mail thread file. This file is already
quite long and keeping it organized allow to understand its content.
SPECIFICATIONS
Some methods defined on mail.thread may actually be called on models
not inheriting from mail.thread . Instead of having model methods on mail
thread receiving a records parameter it seems better to have those available
directly on BaseModel.
Move static_message_track on BaseModel in models.py. This method is now called
_mail_track, to be coherent with othe rmail-related naming. It is used in
accounting to track values in line model that does not inherit from mail.
thread. Update accounting accordingly (followup of d862965).
Move _message_get_default_recipients_on_records in models.py. Renaming it
_message_get_default_recipients() allow to be compatible with current behavior
and current override available in some addons (like CRM, event, ...).
Move _notify_get_reply_to_on_records in models.py. Renaming it
_notify_get_reply_to() allows to be shorter and coherent.
Move _alias_check_contact_on_record in models.py. Renaming it
_alias_check_contact_() allows to be shorter and coherent. Its override in
hr is also moved on BaseModel.
LINKS
Task ID-2327096 (code cleaning)
PR #56631
X-original-commit: f5df1ed912455e5ed52a65df3149f30a9d424de0
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -120,28 +120,3 @@ class AliasMixin(models.AbstractModel):
|
||||
else:
|
||||
record_values[fname] = values.get(fname)
|
||||
return alias_values, record_values
|
||||
|
||||
# --------------------------------------------------
|
||||
# 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
|
||||
|
||||
@@ -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',))
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -574,38 +574,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
|
||||
@@ -624,7 +592,7 @@ class MailThread(models.AbstractModel):
|
||||
tracking = dict()
|
||||
for record in self:
|
||||
try:
|
||||
tracking[record.id] = record._message_track(tracked_fields, initial_values[record.id])
|
||||
tracking[record.id] = record._mail_track(tracked_fields, initial_values[record.id])
|
||||
except MissingError:
|
||||
continue
|
||||
|
||||
@@ -648,13 +616,6 @@ class MailThread(models.AbstractModel):
|
||||
|
||||
return tracking
|
||||
|
||||
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)
|
||||
|
||||
def _track_subtype(self, init_values):
|
||||
""" Give the subtypes triggered by the changes on the record according
|
||||
to values that have been updated.
|
||||
@@ -835,13 +796,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
|
||||
@@ -1480,30 +1438,6 @@ class MailThread(models.AbstractModel):
|
||||
# RECIPIENTS MANAGEMENT TOOLS
|
||||
# ------------------------------------------------------
|
||||
|
||||
@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
|
||||
|
||||
def _message_add_suggested_recipient(self, result, partner=None, email=None, reason=''):
|
||||
""" Called by _message_get_suggested_recipients, to add a suggested
|
||||
recipient in the result dictionary. The form is :
|
||||
@@ -2637,90 +2571,6 @@ 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)
|
||||
|
||||
def _notify_email_recipient_values(self, recipient_ids):
|
||||
""" Format email notification recipient values to store on the notification
|
||||
mail.mail. Basic method just set the recipient partners as mail_mail
|
||||
|
||||
@@ -3,15 +3,176 @@
|
||||
|
||||
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_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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user