From 2950ffaa86ef38263e9a4a59a30d0768f82a61fa Mon Sep 17 00:00:00 2001 From: Aline Preillon Date: Tue, 13 Dec 2016 16:52:18 +0100 Subject: [PATCH] [IMP] mail: improve notification management, either email either inbox Currently partners have a boolean field to choose whether to receive notifications only in their Odoo inbox or to receive them in their inbox and by email. This leads to several issues : * if a customer is configured to not receive emails he will not receive any notification on sales orders, leads, ... This is not clearly indicated to the salesman and it is not easy to know how to change that behavior * if an user chooses to receive emails and does not use its inbox a lot of notifications stay in Odoo. The user has to manually set them as done to make them disappear which is redundant. This commit changes that behavior. From now on customers will always receive all notifications by email. Indeed Odoo is not a customer oriented mailbox. Moreover sales orders or discussions on leads send to customers should always be sent by email as it is the standard communication mechanism. Users will be able to choose to receive notifications in Odoo or by email. The choice is no longer inbox or inbox + email, but inbox or email. Choosing one option or the other one depends on the way the user wants to work. Technically the field is moved on the users model and selection keys are renamed. Notification process is modified * notified_partner_ids contains as before specified recipients as well as followers matching the subtype * customers and users working with emails are notified. During that process customers notifications are marked as done to be able to track the email state without having needaction. Users notifications are currently deleted as we do not track their email state. The removal of partner field implies changes in various addons that define partner data with this field set in the values. --- addons/account/tests/test_fiscal_position.py | 4 -- addons/crm/tests/common.py | 1 + addons/mail/data/mail_data.xml | 6 +- addons/mail/data/mail_demo.xml | 70 +------------------ addons/mail/models/mail_message.py | 9 ++- addons/mail/models/res_partner.py | 9 +-- addons/mail/models/res_users.py | 11 ++- .../static/src/js/many2many_tags_email.js | 3 +- addons/mail/tests/common.py | 12 ++-- addons/mail/tests/test_mail_features.py | 12 ++-- addons/mail/tests/test_message_read.py | 2 +- addons/mail/views/res_partner_views.xml | 1 - addons/mail/views/res_users_views.xml | 4 +- addons/mrp/tests/common.py | 4 +- addons/portal/data/portal_demo.xml | 2 +- addons/procurement/tests/common.py | 2 +- addons/project/tests/test_access_rights.py | 2 +- addons/purchase/tests/test_create_picking.py | 2 +- addons/sale/tests/test_sale_common.py | 4 +- addons/stock/tests/common2.py | 4 +- addons/website_blog/tests/common.py | 6 +- .../data/website_partner_demo.xml | 12 ---- 22 files changed, 53 insertions(+), 129 deletions(-) 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 c9fb6a684fd..ef90160a6cc 100644 --- a/addons/crm/tests/common.py +++ b/addons/crm/tests/common.py @@ -19,6 +19,7 @@ class TestCrm(BaseFunctionalTest): '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/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 23e77971004..ac2183d767a 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -801,12 +801,17 @@ class Message(models.Model): # 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.ids), + ('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_email', '!=', 'none')])._notify(self, force_send=force_send, send_after_commit=send_after_commit, user_signature=user_signature) + ])._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 diff --git a/addons/mail/models/res_partner.py b/addons/mail/models/res_partner.py index feaa3848a48..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,6 +132,7 @@ 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', }) 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/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/tests/common.py b/addons/mail/tests/common.py index aad321e94be..3c03fc07401 100644 --- a/addons/mail/tests/common.py +++ b/addons/mail/tests/common.py @@ -21,21 +21,21 @@ class BaseFunctionalTest(common.SavepointCase): 'login': 'ernest', 'email': 'e.e@example.com', 'signature': '--\nErnest', - 'notify_email': 'always', + 'notification_type': 'email', 'groups_id': [(6, 0, [user_group_employee.id])]}) cls.user_public = Users.create({ 'name': 'Bert Tartignole', 'login': 'bert', 'email': 'b.t@example.com', 'signature': 'SignBert', - 'notify_email': 'always', + 'notification_type': 'email', 'groups_id': [(6, 0, [user_group_public.id])]}) cls.user_portal = Users.create({ 'name': 'Chell Gladys', 'login': 'chell', 'email': 'chell@gladys.portal', 'signature': 'SignChell', - 'notify_email': 'always', + 'notification_type': 'email', 'groups_id': [(6, 0, [user_group_portal.id])]}) cls.user_admin = cls.env.user @@ -86,12 +86,10 @@ class TestMail(BaseFunctionalTest): # Test Data for Partners cls.partner_1 = cls.env['res.partner'].create({ 'name': 'Valid Lelitre', - 'email': 'valid.lelitre@agrolait.com', - 'notify_email': 'always'}) + 'email': 'valid.lelitre@agrolait.com'}) cls.partner_2 = cls.env['res.partner'].create({ 'name': 'Valid Poilvache', - 'email': 'valid.other@gmail.com', - 'notify_email': 'always'}) + 'email': 'valid.other@gmail.com'}) TestModel = cls.env['mail.test'].with_context({ 'mail_create_nolog': True, diff --git a/addons/mail/tests/test_mail_features.py b/addons/mail/tests/test_mail_features.py index a4309259ae0..92613f55e51 100644 --- a/addons/mail/tests/test_mail_features.py +++ b/addons/mail/tests/test_mail_features.py @@ -26,6 +26,9 @@ class TestMailFeatures(TestMail): @mute_logger('odoo.addons.mail.models.mail_mail') def test_needaction(self): + # needaction use Inbox notification + (self.user_employee | self.user_admin).write({'notification_type': 'inbox'}) + na_emp1_base = self.test_pigs.sudo(self.user_employee).message_needaction_counter na_emp2_base = self.test_pigs.sudo().message_needaction_counter @@ -97,9 +100,9 @@ class TestMessagePost(TestMail): 'name': 'Attach2', 'datas_fname': 'Attach2', 'datas': 'bWlncmF0aW9uIHRlc3Q=', 'res_model': 'mail.compose.message', 'res_id': 0}) - # partner_2 does not want to receive notification email - self.partner_2.write({'notify_email': 'none'}) - self.user_admin.write({'notify_email': 'always'}) + + self.user_admin.write({'notification_type': 'email'}) + # subscribe second employee to the group to test notifications self.test_pigs.message_subscribe_users(user_ids=[self.env.user.id]) @@ -134,12 +137,13 @@ class TestMessagePost(TestMail): self.assertFalse(self.env['mail.mail'].search([('mail_message_id', '=', msg.message_id)]), 'message_post: mail.mail notifications should have been auto-deleted') - # notification emails: followers + recipients - notify_email=none (partner_2) - author (user_employee) + # notification emails: followers + recipients - author (user_employee) self.assertEqual(set(m['email_from'] for m in self._mails), set(['%s <%s>' % (self.user_employee.name, self.user_employee.email)]), 'message_post: notification email wrong email_from: should use sender email') self.assertEqual(set(m['email_to'][0] for m in self._mails), set(['%s <%s>' % (self.partner_1.name, self.partner_1.email), + '%s <%s>' % (self.partner_2.name, self.partner_2.email), '%s <%s>' % (self.env.user.name, self.env.user.email)])) self.assertFalse(any(len(m['email_to']) != 1 for m in self._mails), 'message_post: notification email should be sent to one partner at a time') diff --git a/addons/mail/tests/test_message_read.py b/addons/mail/tests/test_message_read.py index 152a7dc4706..e68d2e00ca4 100644 --- a/addons/mail/tests/test_message_read.py +++ b/addons/mail/tests/test_message_read.py @@ -10,7 +10,7 @@ class TestMessageRead(TestMail): @mute_logger('odoo.addons.mail.models.mail_mail') def setUp(self): super(TestMessageRead, self).setUp() - self.user_employee.write({'notify_email': 'none'}) + self.user_employee.write({'notification_type': 'inbox'}) self.group_pigs.message_subscribe_users([self.user_employee.id]) self.msg_0 = self.group_pigs.message_post(body='0', subtype='mt_comment') self.msg_1 = self.group_pigs.message_post(body='1', subtype='mt_comment') diff --git a/addons/mail/views/res_partner_views.xml b/addons/mail/views/res_partner_views.xml index bc3dd7faebe..cd3d62cc7a0 100644 --- a/addons/mail/views/res_partner_views.xml +++ b/addons/mail/views/res_partner_views.xml @@ -8,7 +8,6 @@ - diff --git a/addons/mail/views/res_users_views.xml b/addons/mail/views/res_users_views.xml index c8b18ba4f07..d133fb0424b 100644 --- a/addons/mail/views/res_users_views.xml +++ b/addons/mail/views/res_users_views.xml @@ -10,7 +10,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/addons/mrp/tests/common.py b/addons/mrp/tests/common.py index 5f2fc1e2451..d8c82d791ea 100644 --- a/addons/mrp/tests/common.py +++ b/addons/mrp/tests/common.py @@ -24,13 +24,13 @@ class TestMrpCommon(common2.TestStockCommon): 'name': 'Hilda Ferachwal', 'login': 'hilda', 'email': 'h.h@example.com', - 'notify_email': 'none', + 'notification_type': 'inbox', 'groups_id': [(6, 0, [user_group_mrp_user.id])]}) cls.user_mrp_manager = Users.create({ 'name': 'Gary Youngwomen', 'login': 'gary', 'email': 'g.g@example.com', - 'notify_email': 'none', + 'notification_type': 'inbox', 'groups_id': [(6, 0, [user_group_mrp_manager.id])]}) cls.workcenter_1 = cls.env['mrp.workcenter'].create({ diff --git a/addons/portal/data/portal_demo.xml b/addons/portal/data/portal_demo.xml index 2e069dfe883..85cc1e0b6d2 100644 --- a/addons/portal/data/portal_demo.xml +++ b/addons/portal/data/portal_demo.xml @@ -8,7 +8,6 @@ demo.portal@yourcompany.example.com - none Vivegnis 4683 @@ -19,6 +18,7 @@ portal portal + inbox --
Mr Demo Portal]]>
diff --git a/addons/procurement/tests/common.py b/addons/procurement/tests/common.py index 8dda880b038..a5981c3f88a 100644 --- a/addons/procurement/tests/common.py +++ b/addons/procurement/tests/common.py @@ -23,5 +23,5 @@ class TestStockCommon(common.TestProductCommon): 'name': 'Fabricette Manivelle', 'login': 'fabricette', 'email': 'f.f@example.com', - 'notify_email': 'none', + 'notification_type': 'inbox', 'groups_id': [(6, 0, [user_group_employee.id])]}) diff --git a/addons/project/tests/test_access_rights.py b/addons/project/tests/test_access_rights.py index 74d17cad5a1..0e3cc8cfb6e 100644 --- a/addons/project/tests/test_access_rights.py +++ b/addons/project/tests/test_access_rights.py @@ -15,7 +15,7 @@ class TestPortalProjectBase(TestProjectBase): 'login': 'noemie', 'email': 'n.n@example.com', 'signature': '--\nNoemie', - 'notify_email': 'always', + 'notification_type': 'email', 'groups_id': [(6, 0, [])]}) self.task_3 = self.env['project.task'].with_context({'mail_create_nolog': True}).create({ diff --git a/addons/purchase/tests/test_create_picking.py b/addons/purchase/tests/test_create_picking.py index 0d4833f912b..383b250907a 100644 --- a/addons/purchase/tests/test_create_picking.py +++ b/addons/purchase/tests/test_create_picking.py @@ -20,7 +20,7 @@ class TestCreatePicking(common.TestProductCommon): 'name': 'Pauline Poivraisselle', 'login': 'pauline', 'email': 'pur@example.com', - 'notify_email': 'none', + 'notification_type': 'inbox', 'groups_id': [(6, 0, [res_users_purchase_user.id])]}) self.po_vals = { diff --git a/addons/sale/tests/test_sale_common.py b/addons/sale/tests/test_sale_common.py index 0544917f249..85ecdeac108 100644 --- a/addons/sale/tests/test_sale_common.py +++ b/addons/sale/tests/test_sale_common.py @@ -15,7 +15,7 @@ class TestSale(AccountingTestCase): 'login': 'manager', 'email': 'a.m@example.com', 'signature': '--\nAndreww', - 'notify_email': 'always', + 'notification_type': 'email', 'groups_id': [(6, 0, [group_manager.id])] }) self.user = self.env['res.users'].create({ @@ -23,7 +23,7 @@ class TestSale(AccountingTestCase): 'login': 'user', 'email': 'm.u@example.com', 'signature': '--\nMark', - 'notify_email': 'always', + 'notification_type': 'email', 'groups_id': [(6, 0, [group_user.id])] }) # create quotation with differend kinds of products (all possible combinations) diff --git a/addons/stock/tests/common2.py b/addons/stock/tests/common2.py index c6654dec903..10281b408e8 100644 --- a/addons/stock/tests/common2.py +++ b/addons/stock/tests/common2.py @@ -59,13 +59,13 @@ class TestStockCommon(common.TestProductCommon): 'name': 'Pauline Poivraisselle', 'login': 'pauline', 'email': 'p.p@example.com', - 'notify_email': 'none', + 'notification_type': 'inbox', 'groups_id': [(6, 0, [user_group_stock_user.id])]}) cls.user_stock_manager = Users.create({ 'name': 'Julie Tablier', 'login': 'julie', 'email': 'j.j@example.com', - 'notify_email': 'none', + 'notification_type': 'inbox', 'groups_id': [(6, 0, [user_group_stock_manager.id])]}) # Warehouses diff --git a/addons/website_blog/tests/common.py b/addons/website_blog/tests/common.py index 078f334e7ff..8e63bb608f9 100644 --- a/addons/website_blog/tests/common.py +++ b/addons/website_blog/tests/common.py @@ -18,20 +18,20 @@ class TestWebsiteBlogCommon(common.TransactionCase): 'name': 'Armande Employee', 'login': 'armande', 'email': 'armande.employee@example.com', - 'notify_email': 'none', + 'notification_type': 'inbox', 'groups_id': [(6, 0, [group_employee_id])] }) self.user_blogmanager = Users.with_context({'no_reset_password': True}).create({ 'name': 'Bastien BlogManager', 'login': 'bastien', 'email': 'bastien.blogmanager@example.com', - 'notify_email': 'none', + 'notification_type': 'inbox', 'groups_id': [(6, 0, [group_blog_manager_id, group_employee_id])] }) self.user_public = Users.with_context({'no_reset_password': True}).create({ 'name': 'Cedric Public', 'login': 'cedric', 'email': 'cedric.public@example.com', - 'notify_email': 'none', + 'notification_type': 'inbox', 'groups_id': [(6, 0, [group_public_id])] }) diff --git a/addons/website_partner/data/website_partner_demo.xml b/addons/website_partner/data/website_partner_demo.xml index aaba2d4ddf0..fce6a8ff4b1 100644 --- a/addons/website_partner/data/website_partner_demo.xml +++ b/addons/website_partner/data/website_partner_demo.xml @@ -238,16 +238,4 @@ Our ERP expertise is since 2005 and we mainly focus on Odoo Implementation acros Best Designers has now emerged serving the Small and Medium Business – SMB’s with lots of Free and Open Source Software's, Our team is proficient to deliver quick and quality solutions. With a blend of experts with proven track record, our enterprise solution Business Consultants, ERP Consultants, Network Engineers, Software Developers, Web Architects, Software Testers and Search Engine Optimizers makes it possible to offer our clients affordable solutions that are both innovative and highly influential. ]]>
- - - none - - - - none - - - - none -