[IMP] various: support multi-emails in '_message_post_after_hook'

PURPOSE

Be defensive when dealing with email fields, notably when having multi-emails
or email field containing an already-formatted email.

SPECIFICATIONS

Post-message hook is used in various apps to link records to a newly created
created partner. This is the case notably when used with a template as it
creates partner on the fly based on emails to always handle partners.

We now check either the complete 'email', either the normalized version of
it to avoid comparison issues with multi emails and formatted emails. As
'email_normalized' now supports multi-emails by storing the first found one
it helps finding the partner.

Task-2612945 (Mail: Defensive email formatting)

X-original-commit: odoo/odoo@e5ad9e0371
Part-of: odoo/odoo#134934
This commit is contained in:
Thibault Delavallée
2023-09-11 15:22:09 +00:00
parent 881c5ba5b4
commit 9b33fa5627
4 changed files with 46 additions and 26 deletions
+9 -4
View File
@@ -2036,12 +2036,17 @@ class Lead(models.Model):
# we consider that posting a message with a specified recipient (not a follower, a specific one)
# on a document without customer means that it was created through the chatter using
# suggested recipients. This heuristic allows to avoid ugly hacks in JS.
new_partner = message.partner_ids.filtered(lambda partner: partner.email == self.email_from)
new_partner = message.partner_ids.filtered(
lambda partner: partner.email == self.email_from or (self.email_normalized and partner.email_normalized == self.email_normalized)
)
if new_partner:
if new_partner[0].email_normalized:
email_domain = ('email_normalized', '=', new_partner[0].email_normalized)
else:
email_domain = ('email_from', '=', new_partner[0].email)
self.search([
('partner_id', '=', False),
('email_from', '=', new_partner.email),
('stage_id.fold', '=', False)]).write({'partner_id': new_partner.id})
('partner_id', '=', False), email_domain, ('stage_id.fold', '=', False)
]).write({'partner_id': new_partner[0].id})
return super(Lead, self)._message_post_after_hook(message, msg_vals)
def _message_partner_info_from_emails(self, emails, link_mail=False):
+11 -6
View File
@@ -4,7 +4,7 @@
from dateutil.relativedelta import relativedelta
from odoo import _, api, fields, models, SUPERUSER_ID
from odoo.tools import format_date
from odoo.tools import format_date, email_normalize
from odoo.exceptions import AccessError, ValidationError
@@ -324,13 +324,18 @@ class EventRegistration(models.Model):
# we consider that posting a message with a specified recipient (not a follower, a specific one)
# on a document without customer means that it was created through the chatter using
# suggested recipients. This heuristic allows to avoid ugly hacks in JS.
new_partner = message.partner_ids.filtered(lambda partner: partner.email == self.email)
email_normalized = email_normalize(self.email)
new_partner = message.partner_ids.filtered(
lambda partner: partner.email == self.email or (email_normalized and partner.email_normalized == email_normalized)
)
if new_partner:
if new_partner[0].email_normalized:
email_domain = ('email', 'in', [new_partner[0].email, new_partner[0].email_normalized])
else:
email_domain = ('email', '=', new_partner[0].email)
self.search([
('partner_id', '=', False),
('email', '=', new_partner.email),
('state', 'not in', ['cancel']),
]).write({'partner_id': new_partner.id})
('partner_id', '=', False), email_domain, ('state', 'not in', ['cancel']),
]).write({'partner_id': new_partner[0].id})
return super(EventRegistration, self)._message_post_after_hook(message, msg_vals)
# ------------------------------------------------------------
+12 -6
View File
@@ -539,16 +539,22 @@ class Applicant(models.Model):
# we consider that posting a message with a specified recipient (not a follower, a specific one)
# on a document without customer means that it was created through the chatter using
# suggested recipients. This heuristic allows to avoid ugly hacks in JS.
new_partner = message.partner_ids.filtered(lambda partner: partner.email == self.email_from)
email_normalized = tools.email_normalize(self.email_from)
new_partner = message.partner_ids.filtered(
lambda partner: partner.email == self.email_from or (email_normalized and partner.email_normalized == email_normalized)
)
if new_partner:
if new_partner.create_date.date() == fields.Date.today():
new_partner.write({
if new_partner[0].create_date.date() == fields.Date.today():
new_partner[0].write({
'name': self.partner_name or self.email_from,
})
if new_partner[0].email_normalized:
email_domain = ('email_from', 'in', [new_partner[0].email, new_partner[0].email_normalized])
else:
email_domain = ('email_from', '=', new_partner[0].email)
self.search([
('partner_id', '=', False),
('email_from', '=', new_partner.email),
('stage_id.fold', '=', False)]).write({'partner_id': new_partner.id})
('partner_id', '=', False), email_domain, ('stage_id.fold', '=', False)
]).write({'partner_id': new_partner[0].id})
return super(Applicant, self)._message_post_after_hook(message, msg_vals)
def create_employee_from_applicant(self):
@@ -5,7 +5,7 @@ from datetime import timedelta
from pytz import utc
from random import randint
from odoo import api, fields, models
from odoo import api, fields, models, tools
from odoo.addons.http_routing.models.ir_http import slug
from odoo.osv import expression
from odoo.tools.mail import is_html_empty
@@ -472,15 +472,19 @@ class Track(models.Model):
# Contact(s) created from chatter set on track : we verify if at least one is the expected contact
# linked to the track. (created from contact_email if any, then partner_email if any)
main_email = self.contact_email or self.partner_email
if main_email:
new_partner = message.partner_ids.filtered(lambda partner: partner.email == main_email)
if new_partner:
main_email_string = 'contact_email' if self.contact_email else 'partner_email'
self.search([
('partner_id', '=', False),
(main_email_string, '=', new_partner.email),
('stage_id.is_cancel', '=', False),
]).write({'partner_id': new_partner.id})
main_email_normalized = tools.email_normalize(main_email)
new_partner = message.partner_ids.filtered(
lambda partner: partner.email == main_email or (main_email_normalized and partner.email_normalized == main_email_normalized)
)
if new_partner:
mail_email_fname = 'contact_email' if self.contact_email else 'partner_email'
if new_partner[0].email_normalized:
email_domain = (mail_email_fname, 'in', [new_partner[0].email, new_partner[0].email_normalized])
else:
email_domain = (mail_email_fname, '=', new_partner[0].email)
self.search([
('partner_id', '=', False), email_domain, ('stage_id.is_cancel', '=', False),
]).write({'partner_id': new_partner[0].id})
return super(Track, self)._message_post_after_hook(message, msg_vals)
def _track_template(self, changes):