diff --git a/addons/mail/data/mail_channel_data.xml b/addons/mail/data/mail_channel_data.xml
index 1f6a89308c2..185e342ef58 100644
--- a/addons/mail/data/mail_channel_data.xml
+++ b/addons/mail/data/mail_channel_data.xml
@@ -4,7 +4,7 @@
general
-
+
General announcements for all employees.
@@ -12,7 +12,7 @@
mail.channel
-
+
email
Welcome to Odoo!
diff --git a/addons/mail/data/mail_channel_demo.xml b/addons/mail/data/mail_channel_demo.xml
index 42c6833d159..a38123f80c7 100644
--- a/addons/mail/data/mail_channel_demo.xml
+++ b/addons/mail/data/mail_channel_demo.xml
@@ -23,7 +23,7 @@
Selling a training session and selling the products after the training session is more efficient than directly selling a pack with the training session and the products.
]]>
comment
-
+
@@ -33,7 +33,7 @@
I noted I can not manage efficiently my pipeline when I have more than 50 opportunities in the qualification stage.Any advice on this? How do you organize your activities with more than 50 opportunities?
]]>
comment
-
+
@@ -44,7 +44,7 @@
comment
-
+
@@ -53,7 +53,7 @@
mail.channel
-
+
Great news!
@@ -70,7 +70,7 @@
mail.channel
-
+
Your monthly meal vouchers arrived. You can get them at the HR's office.
This month you also get 250 EUR of eco-vouchers if you have been in the company for more than a year.
]]>
comment
@@ -81,7 +81,7 @@
mail.channel
-
+
Thanks! Could you please remind me where is Christine's office, if I may ask? I'm new here!]]>
comment
@@ -92,7 +92,7 @@
mail.channel
-
+
Building B3, second floor on the right :-).]]>
comment
@@ -158,7 +158,7 @@
]]>
comment
-
+
diff --git a/addons/mail/models/mail_activity.py b/addons/mail/models/mail_activity.py
index 8d0d7ad532c..1ac59a08f3c 100644
--- a/addons/mail/models/mail_activity.py
+++ b/addons/mail/models/mail_activity.py
@@ -7,7 +7,7 @@ from dateutil.relativedelta import relativedelta
import logging
import pytz
-from odoo import api, exceptions, fields, models, _
+from odoo import api, exceptions, fields, models, _, Command
from odoo.osv import expression
from odoo.tools.misc import clean_context
@@ -546,7 +546,7 @@ class MailActivity(models.Model):
},
subtype_id=self.env['ir.model.data'].xmlid_to_res_id('mail.mt_activities'),
mail_activity_type_id=activity.activity_type_id.id,
- attachment_ids=[(4, attachment_id) for attachment_id in attachment_ids] if attachment_ids else [],
+ attachment_ids=[Command.link(attachment_id) for attachment_id in attachment_ids] if attachment_ids else [],
)
# Moving the attachments in the message
diff --git a/addons/mail/models/mail_channel.py b/addons/mail/models/mail_channel.py
index f0c4f81015b..10146ff98e8 100644
--- a/addons/mail/models/mail_channel.py
+++ b/addons/mail/models/mail_channel.py
@@ -6,7 +6,7 @@ import logging
import re
from uuid import uuid4
-from odoo import _, api, fields, models, modules, tools
+from odoo import _, api, fields, models, modules, tools, Command
from odoo.exceptions import UserError, ValidationError
from odoo.osv import expression
from odoo.tools import ormcache, formataddr
@@ -68,7 +68,7 @@ class Channel(models.Model):
return res
def _default_channel_last_seen_partner_ids(self):
- return [(0, 0, {"partner_id": self.env.user.partner_id.id})]
+ return [Command.create({"partner_id": self.env.user.partner_id.id})]
def _get_default_image(self):
image_path = modules.get_module_resource('mail', 'static/src/img', 'groupdefault.png')
@@ -186,7 +186,7 @@ class Channel(models.Model):
missing_partner_ids = set(self.mapped('moderator_ids.partner_id').ids) - set(self.mapped('channel_last_seen_partner_ids.partner_id').ids)
if missing_partner_ids:
self.channel_last_seen_partner_ids = [
- (0, 0, {'partner_id': partner_id})
+ Command.create({'partner_id': partner_id})
for partner_id in missing_partner_ids
]
@@ -278,7 +278,7 @@ class Channel(models.Model):
self.ensure_one()
channel_partner = self.mapped('channel_last_seen_partner_ids').filtered(lambda cp: cp.partner_id == self.env.user.partner_id)
if not channel_partner:
- return self.write({'channel_last_seen_partner_ids': [(0, 0, {'partner_id': self.env.user.partner_id.id})]})
+ return self.write({'channel_last_seen_partner_ids': [Command.create({'partner_id': self.env.user.partner_id.id})]})
return False
def action_unfollow(self):
@@ -286,7 +286,7 @@ class Channel(models.Model):
def _action_unfollow(self, partner):
channel_info = self.channel_info('unsubscribe')[0] # must be computed before leaving the channel (access rights)
- result = self.write({'channel_partner_ids': [(3, partner.id)]})
+ result = self.write({'channel_partner_ids': [Command.unlink(partner.id)]})
# side effect of unsubscribe that wasn't taken into account because
# channel_info is called before actually unpinning the channel
channel_info['is_pinned'] = False
@@ -444,7 +444,7 @@ class Channel(models.Model):
'author_id': self.env.user.partner_id.id,
'body_html': view._render({'channel': self, 'partner': partner}, engine='ir.qweb', minimal_qcontext=True),
'subject': _("Guidelines of channel %s", self.name),
- 'recipient_ids': [(4, partner.id)]
+ 'recipient_ids': [Command.link(partner.id)]
}
mail = self.env['mail.mail'].sudo().create(create_values)
return True
@@ -461,9 +461,9 @@ class Channel(models.Model):
('email', 'in', splitted_emails),
('channel_id', 'in', self.ids)
])
- cmds = [(1, record.id, {'status': status}) for record in moderated]
+ cmds = [Command.update(record.id, {'status': status}) for record in moderated]
not_moderated = [email for email in splitted_emails if email not in moderated.mapped('email')]
- cmds += [(0, 0, {'email': email, 'status': status}) for email in not_moderated]
+ cmds += [Command.create({'email': email, 'status': status}) for email in not_moderated]
return self.write({'moderation_ids': cmds})
#------------------------------------------------------
@@ -683,7 +683,7 @@ class Channel(models.Model):
else:
# create a new one
channel = self.create({
- 'channel_partner_ids': [(4, partner_id) for partner_id in partners_to],
+ 'channel_partner_ids': [Command.link(partner_id) for partner_id in partners_to],
'public': 'private',
'channel_type': 'chat',
'email_send': False,
@@ -827,7 +827,7 @@ class Channel(models.Model):
# add the partner
for channel in self:
partners_to_add = partners - channel.channel_partner_ids
- channel.write({'channel_last_seen_partner_ids': [(0, 0, {'partner_id': partner_id}) for partner_id in partners_to_add.ids]})
+ channel.write({'channel_last_seen_partner_ids': [Command.create({'partner_id': partner_id}) for partner_id in partners_to_add.ids]})
for partner in partners_to_add:
if partner.id != self.env.user.partner_id.id:
notification = _('') % {
@@ -937,7 +937,7 @@ class Channel(models.Model):
'name': name,
'public': privacy,
'email_send': False,
- 'channel_partner_ids': [(4, self.env.user.partner_id.id)]
+ 'channel_partner_ids': [Command.link(self.env.user.partner_id.id)]
})
notification = _('') % (new_channel.id, new_channel.name,)
new_channel.message_post(body=notification, message_type="notification", subtype_xmlid="mail.mt_comment")
diff --git a/addons/mail/models/mail_followers.py b/addons/mail/models/mail_followers.py
index 6c526375584..e025f4a75a7 100644
--- a/addons/mail/models/mail_followers.py
+++ b/addons/mail/models/mail_followers.py
@@ -4,7 +4,7 @@
from collections import defaultdict
import itertools
-from odoo import api, fields, models
+from odoo import api, fields, models, Command
class Followers(models.Model):
@@ -361,30 +361,30 @@ GROUP BY fol.id%s%s""" % (
new.setdefault(res_id, list()).append({
'res_model': res_model,
'partner_id': partner_id,
- 'subtype_ids': [(6, 0, partner_subtypes[partner_id])],
+ 'subtype_ids': [Command.set(partner_subtypes[partner_id])],
})
elif existing_policy in ('replace', 'update'):
fol_id, sids = next(((key, val[3]) for key, val in data_fols.items() if val[0] == res_id and val[1] == partner_id), (False, []))
new_sids = set(partner_subtypes[partner_id]) - set(sids)
old_sids = set(sids if sids[0] is not None else []) - set(partner_subtypes[partner_id])
if fol_id and new_sids:
- update[fol_id] = {'subtype_ids': [(4, sid) for sid in new_sids]}
+ update[fol_id] = {'subtype_ids': [Command.link(sid) for sid in new_sids]}
if fol_id and old_sids and existing_policy == 'replace':
- update[fol_id] = {'subtype_ids': [(3, sid) for sid in old_sids]}
+ update[fol_id] = {'subtype_ids': [Command.unlink(sid) for sid in old_sids]}
for channel_id in set(channel_ids or []):
if channel_id not in doc_cids[res_id]:
new.setdefault(res_id, list()).append({
'res_model': res_model,
'channel_id': channel_id,
- 'subtype_ids': [(6, 0, channel_subtypes[channel_id])],
+ 'subtype_ids': [Command.set(channel_subtypes[channel_id])],
})
elif existing_policy in ('replace', 'update'):
fol_id, sids = next(((key, val[3]) for key, val in data_fols.items() if val[0] == res_id and val[2] == channel_id), (False, []))
new_sids = set(channel_subtypes[channel_id]) - set(sids)
old_sids = set(sids) - set(channel_subtypes[channel_id])
if fol_id and new_sids:
- update[fol_id] = {'subtype_ids': [(4, sid) for sid in new_sids]}
+ update[fol_id] = {'subtype_ids': [Command.link(sid) for sid in new_sids]}
if fol_id and old_sids and existing_policy == 'replace':
- update[fol_id] = {'subtype_ids': [(3, sid) for sid in old_sids]}
+ update[fol_id] = {'subtype_ids': [Command.unlink(sid) for sid in old_sids]}
return new, update
diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py
index 18340b4cb01..9612188de73 100644
--- a/addons/mail/models/mail_message.py
+++ b/addons/mail/models/mail_message.py
@@ -8,7 +8,7 @@ from binascii import Error as binascii_error
from collections import defaultdict
from operator import itemgetter
-from odoo import _, api, fields, models, modules, tools
+from odoo import _, api, Command, fields, models, modules, tools
from odoo.exceptions import AccessError, UserError
from odoo.http import request
from odoo.osv import expression
@@ -761,7 +761,7 @@ class Message(models.Model):
partner_id = self.env.user.partner_id.id
starred_messages = self.search([('starred_partner_ids', 'in', partner_id)])
- starred_messages.write({'starred_partner_ids': [(3, partner_id)]})
+ starred_messages.write({'starred_partner_ids': [Command.unlink(partner_id)]})
ids = [m.id for m in starred_messages]
notification = {'type': 'toggle_star', 'message_ids': ids, 'starred': False}
@@ -775,9 +775,9 @@ class Message(models.Model):
self.check_access_rule('read')
starred = not self.starred
if starred:
- self.sudo().write({'starred_partner_ids': [(4, self.env.user.partner_id.id)]})
+ self.sudo().write({'starred_partner_ids': [Command.link(self.env.user.partner_id.id)]})
else:
- self.sudo().write({'starred_partner_ids': [(3, self.env.user.partner_id.id)]})
+ self.sudo().write({'starred_partner_ids': [Command.unlink(self.env.user.partner_id.id)]})
notification = {'type': 'toggle_star', 'message_ids': [self.id], 'starred': starred}
self.env['bus.bus'].sendone((self._cr.dbname, 'res.partner', self.env.user.partner_id.id), notification)
diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py
index 59c9bba48c4..68078157dc7 100644
--- a/addons/mail/models/mail_template.py
+++ b/addons/mail/models/mail_template.py
@@ -5,7 +5,7 @@ import base64
import logging
-from odoo import _, api, fields, models, tools
+from odoo import _, api, fields, models, tools, Command
from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
@@ -245,8 +245,8 @@ class MailTemplate(models.Model):
# create a mail_mail based on values, without attachments
values = self.generate_email(res_id, ['subject', 'body_html', 'email_from', 'email_to', 'partner_to', 'email_cc', 'reply_to', 'scheduled_date'])
- values['recipient_ids'] = [(4, pid) for pid in values.get('partner_ids', list())]
- values['attachment_ids'] = [(4, aid) for aid in values.get('attachment_ids', list())]
+ values['recipient_ids'] = [Command.link(pid) for pid in values.get('partner_ids', list())]
+ values['attachment_ids'] = [Command.link(aid) for aid in values.get('attachment_ids', list())]
values.update(email_values or {})
attachment_ids = values.pop('attachment_ids', [])
attachments = values.pop('attachments', [])
diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py
index c92584ab9e8..c9058f9db63 100644
--- a/addons/mail/models/mail_thread.py
+++ b/addons/mail/models/mail_thread.py
@@ -23,7 +23,7 @@ from lxml import etree
from werkzeug import urls
from xmlrpc import client as xmlrpclib
-from odoo import _, api, exceptions, fields, models, tools, registry, SUPERUSER_ID
+from odoo import _, api, exceptions, fields, models, tools, registry, SUPERUSER_ID, Command
from odoo.exceptions import MissingError
from odoo.osv import expression
@@ -1665,7 +1665,7 @@ class MailThread(models.AbstractModel):
if not self.env.user.has_group('base.group_user'):
attachment_ids = filtered_attachment_ids.ids
- m2m_attachment_ids += [(4, id) for id in attachment_ids]
+ m2m_attachment_ids += [Command.link(id) for id in attachment_ids]
# Handle attachments parameter, that is a dictionary of attachments
if attachments: # generate
@@ -2064,8 +2064,8 @@ class MailThread(models.AbstractModel):
# Avoid warnings about non-existing fields
for x in ('from', 'to', 'cc', 'canned_response_ids'):
create_values.pop(x, None)
- create_values['partner_ids'] = [(4, pid) for pid in create_values.get('partner_ids', [])]
- create_values['channel_ids'] = [(4, cid) for cid in create_values.get('channel_ids', [])]
+ create_values['partner_ids'] = [Command.link(pid) for pid in create_values.get('partner_ids', [])]
+ create_values['channel_ids'] = [Command.link(cid) for cid in create_values.get('channel_ids', [])]
create_values_list.append(create_values)
if 'default_child_ids' in self._context:
ctx = {key: val for key, val in self._context.items() if key != 'default_child_ids'}
@@ -2104,7 +2104,7 @@ class MailThread(models.AbstractModel):
message_values = {}
if rdata['channels']:
- message_values['channel_ids'] = [(6, 0, [r['id'] for r in rdata['channels']])]
+ message_values['channel_ids'] = [Command.set([r['id'] for r in rdata['channels']])]
self._notify_record_by_inbox(message, rdata, msg_vals=msg_vals, **kwargs)
if notify_by_email:
@@ -2124,7 +2124,7 @@ class MailThread(models.AbstractModel):
"""
channel_ids = [r['id'] for r in recipients_data['channels']]
if channel_ids:
- message.write({'channel_ids': [(6, 0, channel_ids)]})
+ message.write({'channel_ids': [Command.set(channel_ids)]})
inbox_pids = [r['id'] for r in recipients_data['partners'] if r['notif'] == 'inbox']
if inbox_pids:
@@ -2240,7 +2240,7 @@ class MailThread(models.AbstractModel):
create_values = {
'body_html': mail_body,
'subject': mail_subject,
- 'recipient_ids': [(4, pid) for pid in recipient_ids],
+ 'recipient_ids': [Command.link(pid) for pid in recipient_ids],
}
if email_to:
create_values['email_to'] = email_to
diff --git a/addons/mail/models/res_users.py b/addons/mail/models/res_users.py
index ba8e9def72d..cd19198a4c8 100644
--- a/addons/mail/models/res_users.py
+++ b/addons/mail/models/res_users.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo import _, api, exceptions, fields, models, modules
+from odoo import _, api, exceptions, fields, models, modules, Command
from odoo.addons.base.models.res_users import is_selection_groups
@@ -110,7 +110,7 @@ GROUP BY channel_moderator.res_users_id""", [tuple(self.ids)])
updates from public channels until they manually un-subscribe themselves.
"""
self.mapped('partner_id.channel_ids').filtered(lambda c: c.public != 'public').write({
- 'channel_partner_ids': [(3, pid) for pid in self.mapped('partner_id').ids]
+ 'channel_partner_ids': [Command.unlink(pid) for pid in self.mapped('partner_id').ids]
})
@api.model
diff --git a/addons/mail/security/mail_security.xml b/addons/mail/security/mail_security.xml
index 565af06b20a..5f48516a4a1 100644
--- a/addons/mail/security/mail_security.xml
+++ b/addons/mail/security/mail_security.xml
@@ -5,7 +5,7 @@
Mail.channel: access only public and joined groups
-
+
['|', '|',
('public', '=', 'public'),
'&', ('public', '=', 'private'), ('channel_partner_ids', 'in', [user.partner_id.id]),
@@ -16,7 +16,7 @@
mail.notifications: group_user: write its own entries
-
+
[('res_partner_id', '=', user.partner_id.id)]
@@ -27,14 +27,14 @@
mail.message.subtype: portal/public: read public subtypes
[('internal', '=', False)]
-
+
mail.activity: user: write/unlink only (created or assigned)
['|', ('user_id', '=', user.id), ('create_uid', '=', user.id)]
-
+
diff --git a/addons/mail/tests/test_mail_full_composer.py b/addons/mail/tests/test_mail_full_composer.py
index 35dea3ae581..1456dba505a 100644
--- a/addons/mail/tests/test_mail_full_composer.py
+++ b/addons/mail/tests/test_mail_full_composer.py
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests.common import tagged, HttpCase
+from odoo import Command
@tagged('-at_install', 'post_install')
@@ -17,7 +18,7 @@ class TestMailFullComposer(HttpCase):
})
testuser = self.env['res.users'].create({
'email': 'testuser@testuser.com',
- 'groups_id': [(6, 0, [self.ref('base.group_user'), self.ref('base.group_partner_manager')])],
+ 'groups_id': [Command.set([self.ref('base.group_user'), self.ref('base.group_partner_manager')])],
'name': 'Test User',
'login': 'testuser',
'password': 'testuser',
diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py
index 8c84376356b..929b5781959 100644
--- a/addons/mail/wizard/mail_compose_message.py
+++ b/addons/mail/wizard/mail_compose_message.py
@@ -5,7 +5,7 @@ import ast
import base64
import re
-from odoo import _, api, fields, models, tools
+from odoo import _, api, fields, models, tools, Command
from odoo.exceptions import UserError
@@ -201,7 +201,7 @@ class MailComposer(models.TransientModel):
else:
new_attachment_ids.append(attachment.id)
new_attachment_ids.reverse()
- wizard.write({'attachment_ids': [(6, 0, new_attachment_ids)]})
+ wizard.write({'attachment_ids': [Command.set(new_attachment_ids)]})
# Mass Mailing
mass_mode = wizard.composition_mode in ('mass_mail', 'mass_post')
@@ -326,7 +326,7 @@ class MailComposer(models.TransientModel):
mail_values['reply_to'] = mail_values['email_from']
# mail_mail values: body -> body_html, partner_ids -> recipient_ids
mail_values['body_html'] = mail_values.get('body', '')
- mail_values['recipient_ids'] = [(4, id) for id in mail_values.pop('partner_ids', [])]
+ mail_values['recipient_ids'] = [Command.link(id) for id in mail_values.pop('partner_ids', [])]
# process attachments: should not be encoded before being processed by message_post / mail_mail create
mail_values['attachments'] = [(name, base64.b64decode(enc_cont)) for name, enc_cont in email_dict.pop('attachments', list())]
@@ -392,7 +392,7 @@ class MailComposer(models.TransientModel):
}
attachment_ids.append(Attachment.create(data_attach).id)
if values.get('attachment_ids', []) or attachment_ids:
- values['attachment_ids'] = [(6, 0, values.get('attachment_ids', []) + attachment_ids)]
+ values['attachment_ids'] = [Command.set(values.get('attachment_ids', []) + attachment_ids)]
else:
default_values = self.with_context(default_composition_mode=composition_mode, default_model=model, default_res_id=res_id).default_get(['composition_mode', 'model', 'res_id', 'parent_id', 'partner_ids', 'subject', 'body', 'email_from', 'reply_to', 'attachment_ids', 'mail_server_id'])
values = dict((key, default_values[key]) for key in ['subject', 'body', 'partner_ids', 'email_from', 'reply_to', 'attachment_ids', 'mail_server_id'] if key in default_values)
@@ -417,7 +417,7 @@ class MailComposer(models.TransientModel):
'subject': record.subject or False,
'body_html': record.body or False,
'model_id': model.id or False,
- 'attachment_ids': [(6, 0, [att.id for att in record.attachment_ids])],
+ 'attachment_ids': [Command.set([att.id for att in record.attachment_ids])],
}
template = self.env['mail.template'].create(values)
# generate the saved template
diff --git a/addons/mail/wizard/mail_compose_message_view.xml b/addons/mail/wizard/mail_compose_message_view.xml
index 1e9b0a693ff..95a78247852 100644
--- a/addons/mail/wizard/mail_compose_message_view.xml
+++ b/addons/mail/wizard/mail_compose_message_view.xml
@@ -4,7 +4,7 @@
mail.compose.message.form
mail.compose.message
-
+