diff --git a/addons/account/tests/test_fiscal_position.py b/addons/account/tests/test_fiscal_position.py index e3c933ea6e0..320c94cca80 100644 --- a/addons/account/tests/test_fiscal_position.py +++ b/addons/account/tests/test_fiscal_position.py @@ -25,21 +25,17 @@ class TestFiscalPosition(common.TransactionCase): self.jc = self.res_partner.create(dict( name="JCVD", vat="BE0477472701", - notify_email="none", country_id=be.id)) self.ben = self.res_partner.create(dict( name="BP", - notify_email="none", country_id=be.id)) self.george = self.res_partner.create(dict( name="George", vat="BE0477472701", - notify_email="none", country_id=fr.id)) self.alberto = self.res_partner.create(dict( name="Alberto", vat="BE0477472701", - notify_email="none", country_id=mx.id)) self.be_nat = self.fp.create(dict( name="BE-NAT", diff --git a/addons/crm/tests/common.py b/addons/crm/tests/common.py index b53b59628d9..ef90160a6cc 100644 --- a/addons/crm/tests/common.py +++ b/addons/crm/tests/common.py @@ -2,9 +2,9 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.tests.common import TransactionCase -from odoo.addons.mail.tests.common import TestMail +from odoo.addons.mail.tests.common import BaseFunctionalTest -class TestCrm(TestMail): +class TestCrm(BaseFunctionalTest): @classmethod def setUpClass(cls): @@ -19,6 +19,7 @@ class TestCrm(TestMail): 'name': 'Riton La Chignole', 'login': 'riton', 'email': 'riton.salesman_all@example.com', + 'notification_type': 'inbox', 'groups_id': [(6, 0, [user_group_employee.id, user_group_salesman_all.id])] }) diff --git a/addons/crm/tests/test_new_lead_notification.py b/addons/crm/tests/test_new_lead_notification.py index f532d4441c8..514be895d3a 100644 --- a/addons/crm/tests/test_new_lead_notification.py +++ b/addons/crm/tests/test_new_lead_notification.py @@ -12,7 +12,7 @@ class NewLeadNotification(TestCrm): # subscribe a partner and a channel to the sales channel with new lead subtype subtype = self.env.ref("crm.mt_salesteam_lead") self.sales_team_1.message_subscribe(partner_ids=[self.user_salesman_all.partner_id.id], subtype_ids=[subtype.id]) - self.sales_team_1.message_subscribe(channel_ids=[self.group_pigs.id], subtype_ids=[subtype.id]) + self.sales_team_1.message_subscribe(channel_ids=[self.channel_listen.id], subtype_ids=[subtype.id]) # Imitate what happens in the controller when somebody creates a new # lead from the website form @@ -27,11 +27,11 @@ class NewLeadNotification(TestCrm): }) # partner and channel should be auto subscribed self.assertIn(self.user_salesman_all.partner_id, lead.message_partner_ids) - self.assertIn(self.group_pigs, lead.message_channel_ids) + self.assertIn(self.channel_listen, lead.message_channel_ids) msg = lead.message_ids[0] self.assertIn(self.user_salesman_all.partner_id, msg.needaction_partner_ids) - self.assertIn(self.group_pigs, msg.channel_ids) + self.assertIn(self.channel_listen, msg.channel_ids) # The user should have a new unread message lead_user = lead.sudo(self.user_salesman_all) diff --git a/addons/mail/data/mail_data.xml b/addons/mail/data/mail_data.xml index f4d9edfda05..36c26f56eb4 100644 --- a/addons/mail/data/mail_data.xml +++ b/addons/mail/data/mail_data.xml @@ -27,9 +27,9 @@ 1000 - - - none + + + inbox diff --git a/addons/mail/data/mail_demo.xml b/addons/mail/data/mail_demo.xml index d158420d056..23050da6405 100644 --- a/addons/mail/data/mail_demo.xml +++ b/addons/mail/data/mail_demo.xml @@ -3,75 +3,9 @@ - + diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py index bd4face91ce..ac2183d767a 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -761,18 +761,16 @@ class Message(models.Model): @api.multi def _notify(self, force_send=False, send_after_commit=True, user_signature=True): - """ Add the related record followers to the destination partner_ids if is not a private message. - Call mail_notification.notify to manage the email sending - """ + """ Compute recipients to notify based on specified recipients and document + followers. Delegate notification to partners to send emails and bus notifications + and to channels to broadcast messages on channels """ group_user = self.env.ref('base.group_user') - # have a sudoed copy to manipulate partners (public can go here with - # website modules like forum / blog / ... + # have a sudoed copy to manipulate partners (public can go here with website modules like forum / blog / ... ) self_sudo = self.sudo() - # TDE CHECK: add partners / channels as arguments to be able to notify a message with / without computation ?? - self.ensure_one() # tde: not sure, just for testinh, will see - partners = self.env['res.partner'] | self.partner_ids - channels = self.env['mail.channel'] | self.channel_ids + self.ensure_one() + partners_sudo = self.env['res.partner'].sudo() | self_sudo.partner_ids + channels_sudo = self.env['mail.channel'].sudo() | self_sudo.channel_ids # all followers of the mail.message document have to be added as partners and notified # and filter to employees only if the subtype is internal @@ -783,28 +781,38 @@ class Message(models.Model): ]).filtered(lambda fol: self.subtype_id in fol.subtype_ids) if self_sudo.subtype_id.internal: followers = followers.filtered(lambda fol: fol.channel_id or (fol.partner_id.user_ids and group_user in fol.partner_id.user_ids[0].mapped('groups_id'))) - channels = self_sudo.channel_ids | followers.mapped('channel_id') - partners = self_sudo.partner_ids | followers.mapped('partner_id') - else: - channels = self_sudo.channel_ids - partners = self_sudo.partner_ids + channels_sudo |= followers.mapped('channel_id') + partners_sudo |= followers.mapped('partner_id') # remove author from notified partners if not self._context.get('mail_notify_author', False) and self_sudo.author_id: - partners = partners - self_sudo.author_id + partners_sudo = partners_sudo - self_sudo.author_id # update message, with maybe custom values message_values = { - 'channel_ids': [(6, 0, channels.ids)], - 'needaction_partner_ids': [(6, 0, partners.ids)] + 'channel_ids': [(6, 0, channels_sudo.ids)], + 'needaction_partner_ids': [(6, 0, partners_sudo.ids)] } if self.model and self.res_id and hasattr(self.env[self.model], 'message_get_message_notify_values'): message_values.update(self.env[self.model].browse(self.res_id).message_get_message_notify_values(self, message_values)) self.write(message_values) # notify partners and channels - partners._notify(self, force_send=force_send, send_after_commit=send_after_commit, user_signature=user_signature) - channels._notify(self) + # those methods are called as SUPERUSER because portal users posting messages + # have no access to partner model. Maybe propagating a real uid could be necessary. + email_channels = channels_sudo.filtered(lambda channel: channel.email_send) + # make a dedicated search on res.users to avoid user_ids.notification_type that will be user_ids.id in [ARRAY] + notif_users = self.env['res.users'].sudo().search([ + ('partner_id', 'in', partners_sudo.ids), + ('notification_type', '=', 'inbox') + ]) + partners_sudo.search([ + '|', + ('id', 'in', (partners_sudo - notif_users.mapped('partner_id')).ids), + ('channel_ids', 'in', email_channels.ids), + ('email', '!=', self_sudo.author_id and self_sudo.author_id.email or self_sudo.email_from), + ])._notify(self, force_send=force_send, send_after_commit=send_after_commit, user_signature=user_signature) + channels_sudo._notify(self) # Discard cache, because child / parent allow reading and therefore # change access rights. diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 8f3e752bccc..4b0b71846e6 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -2134,10 +2134,9 @@ class MailThread(models.AbstractModel): new_channels.setdefault(header_follower.channel_id.id, set()).add(new_subtype.id) # add followers coming from res.users relational fields that are tracked - user_ids = [values[name] for name in user_field_lst if values.get(name)] - user_pids = [user.partner_id.id for user in self.env['res.users'].sudo().browse(user_ids)] - for partner_id in user_pids: - new_partners.setdefault(partner_id, None) + to_add_users = self.env['res.users'].sudo().browse([values[name] for name in user_field_lst if values.get(name)]) + for partner in to_add_users.mapped('partner_id'): + new_partners.setdefault(partner.id, None) for pid, subtypes in new_partners.items(): subtypes = list(subtypes) if subtypes is not None else None @@ -2147,7 +2146,7 @@ class MailThread(models.AbstractModel): self.message_subscribe(channel_ids=[cid], subtype_ids=subtypes, force=(subtypes != None)) # remove the current user from the needaction partner to avoid to notify the author of the message - user_pids = [user_pid for user_pid in user_pids if user_pid != self.env.user.partner_id.id] + user_pids = [user.partner_id.id for user in to_add_users if user != self.env.user and user.notification_type == 'email'] self._message_auto_subscribe_notify(user_pids) return True diff --git a/addons/mail/models/res_partner.py b/addons/mail/models/res_partner.py index ba927ac16ab..8a999fcc896 100644 --- a/addons/mail/models/res_partner.py +++ b/addons/mail/models/res_partner.py @@ -19,14 +19,6 @@ class Partner(models.Model): _mail_mass_mailing = _('Customers') message_bounce = fields.Integer('Bounce', help="Counter of the number of bounced emails for this contact") - notify_email = fields.Selection([ - ('none', 'Never'), - ('always', 'All Messages')], - 'Email Messages and Notifications', required=True, - oldname='notification_email_send', default='always', - help="Policy to receive emails for new messages pushed to your personal Inbox:\n" - "- Never: no emails are sent\n" - "- All Messages: for every notification you receive in your Inbox") opt_out = fields.Boolean( 'Opt-Out', help="If opt-out is checked, this contact has refused to receive emails for mass mailing and marketing campaign. " "Filter 'Available for Mass Mailing' allows users to filter the partners when performing mass mailing.") @@ -140,25 +132,12 @@ class Partner(models.Model): ('res_partner_id', 'in', email.recipient_ids.ids)]) notifications.write({ 'is_email': True, + 'is_read': True, # handle by email discards Inbox notification 'email_status': 'ready', }) @api.multi def _notify(self, message, force_send=False, send_after_commit=True, user_signature=True): - # TDE TODO: model-dependant ? (like customer -> always email ?) - message_sudo = message.sudo() - email_channels = message.channel_ids.filtered(lambda channel: channel.email_send) - self.sudo().search([ - '|', - ('id', 'in', self.ids), - ('channel_ids', 'in', email_channels.ids), - ('email', '!=', message_sudo.author_id and message_sudo.author_id.email or message.email_from), - ('notify_email', '!=', 'none')])._notify_by_email(message, force_send=force_send, send_after_commit=send_after_commit, user_signature=user_signature) - self._notify_by_chat(message) - return True - - @api.multi - def _notify_by_email(self, message, force_send=False, send_after_commit=True, user_signature=True): """ Method to send email linked to notified messages. The recipients are the recordset on which this method is called. diff --git a/addons/mail/models/res_users.py b/addons/mail/models/res_users.py index 1f95c02f078..1c90a56d3cb 100644 --- a/addons/mail/models/res_users.py +++ b/addons/mail/models/res_users.py @@ -23,6 +23,13 @@ class Users(models.Model): ('everyone', 'Everyone'), ('partners', 'Authenticated Partners'), ('followers', 'Followers only')], string='Alias Contact Security', related='alias_id.alias_contact') + notification_type = fields.Selection([ + ('email', 'Handle by Emails'), + ('inbox', 'Handle in Odoo')], + 'Notification Management', required=True, default='email', + help="Policy on how to handle Chatter notifications:\n" + "- Emails: notifications are sent to your email\n" + "- Odoo: notifications appear in your Odoo Inbox") def __init__(self, pool, cr): """ Override of __init__ to add access rights on notification_email_send @@ -32,10 +39,10 @@ class Users(models.Model): init_res = super(Users, self).__init__(pool, cr) # duplicate list to avoid modifying the original reference type(self).SELF_WRITEABLE_FIELDS = list(self.SELF_WRITEABLE_FIELDS) - type(self).SELF_WRITEABLE_FIELDS.extend(['notify_email']) + type(self).SELF_WRITEABLE_FIELDS.extend(['notification_type']) # duplicate list to avoid modifying the original reference type(self).SELF_READABLE_FIELDS = list(self.SELF_READABLE_FIELDS) - type(self).SELF_READABLE_FIELDS.extend(['notify_email']) + type(self).SELF_READABLE_FIELDS.extend(['notification_type']) return init_res @api.model diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv index 79c264ccc98..0bd1697ca87 100644 --- a/addons/mail/security/ir.model.access.csv +++ b/addons/mail/security/ir.model.access.csv @@ -33,7 +33,8 @@ access_mail_template,mail.template,model_mail_template,base.group_user,1,1,1,0 access_mail_template_system,mail.template_system,model_mail_template,base.group_system,1,1,1,1 access_mail_shortcode,mail.shortcode,model_mail_shortcode,base.group_user,1,1,1,1 access_mail_shortcode_portal,mail.shortcode.portal,model_mail_shortcode,base.group_portal,1,0,0,0 -access_mail_test_all,mail.test.all,model_mail_test,base.group_user,1,1,1,1 +access_mail_test_user,mail.test.all,model_mail_test,base.group_user,1,1,1,1 +access_mail_test_portal,mail.test.all,model_mail_test,base.group_portal,1,1,0,0 access_mail_activity_all,mail.activity.all,model_mail_activity,,1,0,0,0 access_mail_activity_user,mail.activity.user,model_mail_activity,base.group_user,1,1,1,1 access_mail_activity_type_all,mail.activity.type.all,model_mail_activity_type,,1,0,0,0 diff --git a/addons/mail/static/src/js/client_action.js b/addons/mail/static/src/js/client_action.js index 822f87dc0a2..82a68e52eb9 100644 --- a/addons/mail/static/src/js/client_action.js +++ b/addons/mail/static/src/js/client_action.js @@ -111,14 +111,6 @@ var ChatAction = Widget.extend(ControlPanelMixin, { var channel_id = $(event.target).data("channel-id"); chat_manager.unsubscribe(chat_manager.get_channel(channel_id)); }, - "click .o_snackbar_undo": function (event) { - event.preventDefault(); - var channel = this.channel; - this.$snackbar.remove(); - this.clear_needactions_def.then(function (msgs_ids) { - chat_manager.undo_mark_as_read(msgs_ids, channel); - }); - }, "click .o_mail_annoying_notification_bar .fa-close": function () { this.$(".o_mail_annoying_notification_bar").slideUp(); }, @@ -425,7 +417,6 @@ var ChatAction = Widget.extend(ControlPanelMixin, { this.messages_separator_position = undefined; // reset value on channel change this.unread_counter = this.channel.unread_counter; this.last_seen_message_id = this.channel.last_seen_message_id; - this.clear_needactions_def = $.Deferred(); if (this.$snackbar) { this.$snackbar.remove(); } @@ -436,14 +427,7 @@ var ChatAction = Widget.extend(ControlPanelMixin, { return this.fetch_and_render_thread().then(function () { // Mark channel's messages as read and clear needactions if (channel.type !== 'static') { - // Display snackbar if needactions have been cleared - if (channel.needaction_counter > 0) { - self.render_snackbar('mail.chat.UndoSnackbar', { - nb_needactions: channel.needaction_counter, - }); - } chat_manager.mark_channel_as_seen(channel); - self.clear_needactions_def = chat_manager.mark_all_as_read(channel); } // Update control panel diff --git a/addons/mail/static/src/js/many2many_tags_email.js b/addons/mail/static/src/js/many2many_tags_email.js index a9fd41a3cd7..bd3957cd5d3 100644 --- a/addons/mail/static/src/js/many2many_tags_email.js +++ b/addons/mail/static/src/js/many2many_tags_email.js @@ -50,8 +50,7 @@ var FieldMany2ManyTagsEmail = form_relational.FieldMany2ManyTags.extend({ var self = this; new Model('res.partner').call("search", [[ ["id", "in", ids], - ["email", "=", false], - ["notify_email", "=", 'always'] ]], + ["email", "=", false] ]], {context: this.build_context()}) .then(function (record_ids) { // valid partner diff --git a/addons/mail/static/src/less/client_action.less b/addons/mail/static/src/less/client_action.less index eb91fd78fb3..53ac45d8d3f 100644 --- a/addons/mail/static/src/less/client_action.less +++ b/addons/mail/static/src/less/client_action.less @@ -167,10 +167,6 @@ cursor: pointer; background-color: darken(@gray, 8%); color: white; - .o_snackbar_undo { - margin-left: 8px; - padding: 8px; - } } } } diff --git a/addons/mail/static/src/xml/client_action.xml b/addons/mail/static/src/xml/client_action.xml index b6701a45cb7..ff2122256cc 100644 --- a/addons/mail/static/src/xml/client_action.xml +++ b/addons/mail/static/src/xml/client_action.xml @@ -113,13 +113,6 @@ - - - -