[FIX] mail: fix mail.mail default values collision
This commit cleans the default_* keys of the context before creating mail.mails
and mail.notifications when notifying the record by email.
Without this change, there can be a collision when the ORM tries to compute
default values for the state field (for example):
- Model "A" has a 'state' field ;
- Create an action that redirects to model "A" form view, setting some default
values in the context such as {'default_state': 'done'} ;
- Model "A" has an inherit on 'mail.thread' and a 'user_id' field to set a
responsible user ;
- Model "A" record is created with a responsible user, who is automatically
notified by email that the record "has been assigned to him" ;
(see mail_thread#_message_auto_subscribe_notify)
- A 'mail.mail' is in turn created ;
- The 'mail.mail' model ALSO has a 'state' field, and the context is propagated
so the ORM will try to assign 'done' to that field, which is an incorrect
value ;
- -> Crash.
If we ensure that the default_* keys are cleaned from the context, the default
values computation of the mail.mail record will not be affected and everything
works fine.
A test was added to ensure this behavior.
Task 2393259
closes odoo/odoo#62589
X-original-commit: 6b6e546ac95d9acb2964121dd52aa2896d31bc33
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
Signed-off-by: awa-odoo <awa-odoo@users.noreply.github.com>
This commit is contained in:
@@ -2212,7 +2212,14 @@ class MailThread(models.AbstractModel):
|
||||
}
|
||||
base_mail_values = self._notify_by_email_add_values(base_mail_values)
|
||||
|
||||
Mail = self.env['mail.mail'].sudo()
|
||||
# Clean the context to get rid of residual default_* keys that could cause issues during
|
||||
# the mail.mail creation.
|
||||
# Example: 'default_state' would refer to the default state of a previously created record
|
||||
# from another model that in turns triggers an assignation notification that ends up here.
|
||||
# This will lead to a traceback when trying to create a mail.mail with this state value that
|
||||
# doesn't exist.
|
||||
SafeMail = self.env['mail.mail'].sudo().with_context(clean_context(self._context))
|
||||
SafeNotification = self.env['mail.notification'].sudo().with_context(clean_context(self._context))
|
||||
emails = self.env['mail.mail'].sudo()
|
||||
|
||||
# loop on groups (customer, portal, user, ... + model specific like group_sale_salesman)
|
||||
@@ -2245,7 +2252,7 @@ class MailThread(models.AbstractModel):
|
||||
if email_to:
|
||||
create_values['email_to'] = email_to
|
||||
create_values.update(base_mail_values) # mail_message_id, mail_server_id, auto_delete, references, headers
|
||||
email = Mail.create(create_values)
|
||||
email = SafeMail.create(create_values)
|
||||
|
||||
if email and recipient_ids:
|
||||
tocreate_recipient_ids = list(recipient_ids)
|
||||
@@ -2272,7 +2279,7 @@ class MailThread(models.AbstractModel):
|
||||
emails |= email
|
||||
|
||||
if notif_create_values:
|
||||
self.env['mail.notification'].sudo().create(notif_create_values)
|
||||
SafeNotification.create(notif_create_values)
|
||||
|
||||
# NOTE:
|
||||
# 1. for more than 50 followers, use the queue system
|
||||
|
||||
@@ -270,6 +270,51 @@ class AdvancedFollowersTest(TestMailCommon):
|
||||
all_defaults)
|
||||
|
||||
|
||||
class AdvancedResponsibleNotifiedTest(TestMailCommon):
|
||||
def setUp(self):
|
||||
super(AdvancedResponsibleNotifiedTest, self).setUp()
|
||||
|
||||
# patch registry to simulate a ready environment so that _message_auto_subscribe_notify
|
||||
# will be executed with the associated notification
|
||||
old = self.env.registry.ready
|
||||
self.env.registry.ready = True
|
||||
self.addCleanup(setattr, self.env.registry, 'ready', old)
|
||||
|
||||
def test_auto_subscribe_notify_email(self):
|
||||
""" Responsible is notified when assigned """
|
||||
partner = self.env['res.partner'].create({"name": "demo1", "email": "demo1@test.com"})
|
||||
notified_user = self.env['res.users'].create({
|
||||
'login': 'demo1',
|
||||
'partner_id': partner.id,
|
||||
'notification_type': 'email',
|
||||
})
|
||||
|
||||
# TODO master: add a 'state' selection field on 'mail.test.track' with a 'done' value to have a complete test
|
||||
# check that 'default_state' context does not collide with mail.mail default values
|
||||
sub = self.env['mail.test.track'].with_user(self.user_employee).with_context({
|
||||
'default_state': 'done',
|
||||
'mail_notify_force_send': False
|
||||
}).create({
|
||||
'name': 'Test',
|
||||
'user_id': notified_user.id,
|
||||
})
|
||||
|
||||
self.assertEqual(sub.message_partner_ids, (self.user_employee.partner_id | notified_user.partner_id))
|
||||
# fetch created "You have been assigned to 'Test'" mail.message
|
||||
mail_message = self.env['mail.message'].search([
|
||||
('model', '=', 'mail.test.track'),
|
||||
('res_id', '=', sub.id),
|
||||
('partner_ids', 'in', partner.id),
|
||||
])
|
||||
self.assertEqual(1, len(mail_message))
|
||||
|
||||
# verify that a mail.mail is attached to it with the correct state ('outgoing')
|
||||
mail_notification = mail_message.notification_ids
|
||||
self.assertEqual(1, len(mail_notification))
|
||||
self.assertTrue(bool(mail_notification.mail_id))
|
||||
self.assertEqual('outgoing', mail_notification.mail_id.state)
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class DuplicateNotificationTest(TestMailCommon):
|
||||
def test_no_duplicate_notification(self):
|
||||
|
||||
Reference in New Issue
Block a user