From 4b68f64473ff12ae66d880d3e4a764cbbd2a0053 Mon Sep 17 00:00:00 2001 From: "Nimesh (Open ERP)" Date: Tue, 18 Sep 2012 14:17:31 +0530 Subject: [PATCH 01/18] [ADD] add context to client action and improve read method for set read message by user. bzr revid: nco@tinyerp.com-20120918084731-eed2ssuzhw7woi78 --- addons/mail/mail_group.py | 2 +- addons/mail/mail_group_view.xml | 1 + addons/mail/mail_message.py | 7 +++++++ addons/mail/mail_message_view.xml | 4 ++-- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py index fe0cc3950ae..c7c51a84a00 100644 --- a/addons/mail/mail_group.py +++ b/addons/mail/mail_group.py @@ -125,7 +125,7 @@ class mail_group(osv.Model): params = { 'search_view_id': search_ref and search_ref[1] or False, 'domain': [('model', '=', 'mail.group'), ('res_id', '=', mail_group_id)], - 'context': {'default_model': 'mail.group', 'default_res_id': mail_group_id}, + 'context': {'default_model': 'mail.group', 'default_res_id': mail_group_id, 'mail_keep_unread':True}, 'res_model': 'mail.message', 'thread_level': 1, } diff --git a/addons/mail/mail_group_view.xml b/addons/mail/mail_group_view.xml index 31beba80ecc..bcd754fed3d 100644 --- a/addons/mail/mail_group_view.xml +++ b/addons/mail/mail_group_view.xml @@ -6,6 +6,7 @@ Discussion Group mail.wall mail.message + {'mail_keep_unread': True} diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 44ce76b94b0..c9340b77cea 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -218,10 +218,17 @@ class mail_message(osv.Model): """ limit = limit or self._message_read_limit context = context or {} + notif_obj = self.pool.get("mail.notification") if not ids: ids = self.search(cr, uid, domain, context=context, limit=limit) messages = self.browse(cr, uid, ids, context=context) + partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id + for msg in messages: + notif_ids = notif_obj.search(cr, uid, [('partner_id', '=', partner_id), ('message_id', '=', msg.id)], context=context) + notif_obj.write(cr, uid, notif_ids, {'read': True}, context=context) + context.update({'mail_keep_unread':False}) + result = [] tree = {} # key: ID, value: record for msg in messages: diff --git a/addons/mail/mail_message_view.xml b/addons/mail/mail_message_view.xml index 914937a34f3..c9806a9db9a 100644 --- a/addons/mail/mail_message_view.xml +++ b/addons/mail/mail_message_view.xml @@ -91,14 +91,14 @@ News Feed mail.wall + 'context': {'default_model': 'res.users', 'default_res_id': uid, 'mail_keep_unread': True} }""/> My Feeds mail.wall + 'context': {'default_model': 'res.users', 'default_res_id': uid, 'mail_keep_unread': True} }""/> From bbf40f3d7eda6e84b012105eb8b5571bd26d177d Mon Sep 17 00:00:00 2001 From: "Nimesh (Open ERP)" Date: Tue, 18 Sep 2012 17:53:59 +0530 Subject: [PATCH 02/18] [IMP] impove the read message to set msg read. bzr revid: nco@tinyerp.com-20120918122359-uppqkoba9xxj8jst --- addons/mail/mail_message.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index c9340b77cea..ae04d81ee4b 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -223,15 +223,12 @@ class mail_message(osv.Model): ids = self.search(cr, uid, domain, context=context, limit=limit) messages = self.browse(cr, uid, ids, context=context) - partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id - for msg in messages: - notif_ids = notif_obj.search(cr, uid, [('partner_id', '=', partner_id), ('message_id', '=', msg.id)], context=context) - notif_obj.write(cr, uid, notif_ids, {'read': True}, context=context) - context.update({'mail_keep_unread':False}) - result = [] tree = {} # key: ID, value: record for msg in messages: + if not context.has_key('mail_keep_unread'): + notif_ids = notif_obj.search(cr, uid, [('message_id', '=', msg.id)], context=context) + notif_obj.write(cr, uid, notif_ids, {'read': True}, context=context) if len(result) < (limit - 1): record = self._message_dict_get(cr, uid, msg, context=context) if thread_level and msg.parent_id: From 10107c6ce6293b714c5b821c628e6f83ea80ed24 Mon Sep 17 00:00:00 2001 From: "Nimesh (Open ERP)" Date: Wed, 19 Sep 2012 14:01:23 +0530 Subject: [PATCH 03/18] [ADD] add unit test for message read. bzr revid: nco@tinyerp.com-20120919083123-mmbwbpc3w3oszptg --- addons/mail/tests/test_mail.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py index 57a59e2595f..a90d17913bd 100644 --- a/addons/mail/tests/test_mail.py +++ b/addons/mail/tests/test_mail.py @@ -677,3 +677,30 @@ class test_mail(TestMailMockups): msg1.refresh() # Test: msg1 has Bert as voter self.assertEqual(set(msg1.vote_user_ids), set([user_bert]), 'after unvoting for Admin, Bert is not the voter') + + def test_70_read_unread(self): + """ Test designed for the message read or unread feature. """ + cr, uid = self.cr, self.uid + group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id) + user_admin = self.res_users.browse(cr, uid, uid) + + # 0 - Admin + p_a_id = user_admin.partner_id.id + # 1 - Bert Tartopoils, with email, should receive emails for comments and emails + p_b_id = self.res_partner.create(cr, uid, {'name': 'Bert Tartopoils', 'email': 'b@b'}) + # 2 - Carine Poilvache, with email, should never receive emails + p_c_id = self.res_partner.create(cr, uid, {'name': 'Carine Poilvache', 'email': 'c@c', 'notification_email_send': 'email'}) + # 3 - Dédé Grosbedon, without email, to test email verification; should receive emails for every message + p_d_id = self.res_partner.create(cr, uid, {'name': 'Dédé Grosbedon', 'notification_email_send': 'all'}) + + # Subscribe #1, #2 + group_pigs.message_subscribe([p_b_id, p_c_id]) + + msg1 = group_pigs.message_post(body='My Body', subject='1') + context = {'default_model': 'mail.group', 'default_res_id': [self.group_pigs_id]} + self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], thread_level=2, limit=10,context=context) + if not context.has_key('mail_keep_unread'): + notif_ids = self.mail_notification.search(cr, uid, [('partner_id', '=', user_admin.partner_id.id),('message_id', '=', msg1)], context=context) + na_count = len(notif_ids) + self.assertTrue(len(notif_ids), 'unread notifications') + self.mail_notification.write(cr, uid, notif_ids, {'read': True}, context=context) From 6c53c3c38b339f830d96e737c92f69a757bf2267 Mon Sep 17 00:00:00 2001 From: "Atul Patel (OpenERP)" Date: Fri, 21 Sep 2012 17:50:11 +0530 Subject: [PATCH 04/18] [FIX]: Fix none context problem bzr revid: atp@tinyerp.com-20120921122011-xmxm32ow5lnwc4al --- addons/mail/tests/test_mail.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py index 25767047269..5d3a100f09b 100644 --- a/addons/mail/tests/test_mail.py +++ b/addons/mail/tests/test_mail.py @@ -694,18 +694,18 @@ class test_mail(TestMailMockups): msg2 = group_pigs.message_post(body='My Body', subject='2') message1 = self.mail_message.browse(cr, uid, msg1) message2 = self.mail_message.browse(cr, uid, msg2) - + context= {} #Test : Groups contain two messages. self.assertEqual(2, len(group_pigs.message_ids), 'group should contain 2 messages') #Read message without key. using bert parner - msg_data1 = self.mail_message.message_read(cr, user_bert.id, ids=[message1.id], domain=[], thread_level=2, limit=10,context={}) + msg_data1 = self.mail_message.message_read(cr, user_bert.id, ids=[message1.id], domain=[], thread_level=2, limit=10,context=context) #check notification For message readable or unread. notif_msg1_ids1 = self.mail_notification.search(cr, uid, [('partner_id', '=', user_bert.partner_id.id),('message_id', '=', message1.id)], context=context) notif_data1 = self.mail_notification.read(cr, uid, notif_msg1_ids1, ['read'])[0]['read'] # Test: Message1 are marked as read. self.assertTrue(notif_data1, 'Message1 are set as read for the user Bert that read it') #Pass key in context for unread message.. - context = {'default_model': 'mail.group', 'default_res_id': [self.group_pigs_id], 'mail_keep_unread': True} + context.update({'default_model': 'mail.group', 'default_res_id': [self.group_pigs_id], 'mail_keep_unread': True}) # Test: New created Message2 are set as unread. msg_data2 = self.mail_message.message_read(cr, uid, ids=[message2.id], domain=[], thread_level=2, limit=10,context=context) #Check Notification For unread message.. From d473364d5269d6b2e26d22ba69d9e054c1a195b2 Mon Sep 17 00:00:00 2001 From: "Atul Patel (OpenERP)" Date: Mon, 24 Sep 2012 10:26:58 +0530 Subject: [PATCH 05/18] [IMP]: Imp test case bzr revid: atp@tinyerp.com-20120924045658-6m1tkjpqm4ztvojf --- addons/mail/tests/test_mail.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py index 5d3a100f09b..94ecdc1be46 100644 --- a/addons/mail/tests/test_mail.py +++ b/addons/mail/tests/test_mail.py @@ -695,6 +695,9 @@ class test_mail(TestMailMockups): message1 = self.mail_message.browse(cr, uid, msg1) message2 = self.mail_message.browse(cr, uid, msg2) context= {} + #Check Before read , number of posted message count are 2. + na_count = self.mail_message._needaction_count(cr, uid, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)]) + self.assertEqual(na_count, 2, 'posted message count does not match needaction count') #Test : Groups contain two messages. self.assertEqual(2, len(group_pigs.message_ids), 'group should contain 2 messages') #Read message without key. using bert parner @@ -712,6 +715,6 @@ class test_mail(TestMailMockups): notif_msg2_ids2 = self.mail_notification.search(cr, uid, [('partner_id', '=', user_admin.partner_id.id),('message_id', '=', message2.id)], context=context) notif_data2 = self.mail_notification.read(cr, uid, notif_msg2_ids2, ['read'])[0]['read'] self.assertFalse(notif_data2, 'Newly created Message2 are set as unread') - # Check there are 1 needaction on mail.message with particular domain + # Check there are 1 needaction after Reading one posted message on mail.message with particular domain. na_count = self.mail_message._needaction_count(cr, uid, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)]) self.assertEqual(na_count, 1, 'posted message count does not match needaction count') From 70c710cb82cf1b12ae8dcd0df3e7d510114f4c05 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Wed, 19 Dec 2012 15:07:48 +0100 Subject: [PATCH 06/18] [IMP] mail: catch exeption if the message body is not converted by html_email_clean. return an error message for rendering and raise the exeption bzr revid: chm@openerp.com-20121219140748-ur02plu65i6ab9rw --- addons/mail/mail_message.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index d545f3782b4..14d3cce031a 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -350,9 +350,15 @@ class mail_message(osv.Model): vote_nb = len(message.vote_user_ids) has_voted = uid in [user.id for user in message.vote_user_ids] + try: + body_html = html_email_clean(message.body) + except Exception: + body_html = '

Encoding Error :
Unable to convert this message (id: %s).

' % message.id + _logger.exception(Exception) + return {'id': message.id, 'type': message.type, - 'body': html_email_clean(message.body or ''), + 'body': body_html, 'model': message.model, 'res_id': message.res_id, 'record_name': message.record_name, From a8540c5b7e7b819a44fccba41ba78a34eff8be66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 20 Dec 2012 15:28:52 +0100 Subject: [PATCH 07/18] [REF] [FIX] mail: refactored auto-set read when viewing chatter widget. Added some tests. Also fixed a bug about message order with anybody else than admin. bzr revid: tde@openerp.com-20121220142852-6sjk03791x829ys3 --- addons/mail/mail_group.py | 5 ++--- addons/mail/mail_message.py | 19 ++++++++++------- addons/mail/static/src/js/mail.js | 1 + addons/mail/tests/test_message_read.py | 29 +++++++++++++++----------- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py index 50f636c3c5b..25654bfed8b 100644 --- a/addons/mail/mail_group.py +++ b/addons/mail/mail_group.py @@ -136,15 +136,14 @@ class mail_group(osv.Model): 'domain': [('model', '=', 'mail.group'), ('res_id', '=', mail_group_id)], 'context': {'default_model': 'mail.group', 'default_res_id': mail_group_id, - 'search_default_message_unread': True, - 'mail_read_keep_unread':True}, + 'search_default_message_unread': True}, 'res_model': 'mail.message', 'thread_level': 1, 'header_description': vals.get('description'), } cobj = self.pool.get('ir.actions.client') newref = cobj.copy(cr, SUPERUSER_ID, ref[1], default={'params': str(params), 'name': vals['name']}, context=context) - mobj.write(cr, SUPERUSER_ID, menu_id, { 'action': 'ir.actions.client,' + str(newref), 'mail_group_id': mail_group_id}, context=context) + mobj.write(cr, SUPERUSER_ID, menu_id, {'action': 'ir.actions.client,' + str(newref), 'mail_group_id': mail_group_id}, context=context) if vals.get('group_ids'): self._subscribe_users(cr, uid, [mail_group_id], context=context) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 831e1e4b162..207b46de5d5 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -492,6 +492,7 @@ class mail_message(osv.Model): message_unload_ids = message_unload_ids if message_unload_ids is not None else [] if message_unload_ids: domain += [('id', 'not in', message_unload_ids)] + notification_obj = self.pool.get('mail.notification') limit = limit or self._message_read_limit message_tree = {} message_list = [] @@ -501,11 +502,6 @@ class mail_message(osv.Model): if ids is None: ids = self.search(cr, uid, domain, context=context, limit=limit) - # if requested: mark messages as read - if context and context.has_key('mail_read_set_read'): - notif_ids = notif_obj.search(cr, uid, [('message_id', '=', msg.id)], context=context) - notif_obj.write(cr, uid, notif_ids, {'read': True}, context=context) - # fetch parent if threaded, sort messages for message in self.browse(cr, uid, ids, context=context): message_id = message.id @@ -534,10 +530,17 @@ class mail_message(osv.Model): message_id_list.sort(key=lambda item: item['id']) message_id_list.insert(0, self._message_read_dict(cr, uid, message_tree[key], context=context)) + # create final ordered message_list based on parent_tree parent_list = parent_tree.items() parent_list = sorted(parent_list, key=lambda item: max([msg.get('id') for msg in item[1]]) if item[1] else item[0], reverse=True) message_list = [message for (key, msg_list) in parent_list for message in msg_list] + # if requested: mark messages as read + if context and context.get('mail_read_set_read'): + message_ids = [message.get('id') for message in message_list] + notif_ids = notification_obj.search(cr, uid, [('partner_id.user_ids', 'in', uid), ('message_id', 'in', message_ids)], context=context) + notification_obj.write(cr, uid, notif_ids, {'read': True}, context=context) + # get the child expandable messages for the tree self._message_read_dict_postprocess(cr, uid, message_list, message_tree, context=context) self._message_read_add_expandables(cr, uid, message_list, message_tree, parent_tree, @@ -605,12 +608,14 @@ class mail_message(osv.Model): model_ids.setdefault(message.get('model'), {}).setdefault(message.get('res_id'), set()).add(message.get('id')) allowed_ids = self._find_allowed_doc_ids(cr, uid, model_ids, context=context) - final_ids = author_ids | partner_ids | allowed_ids + if count: return len(final_ids) else: - return list(final_ids) + # re-construct a list based on ids, because set did not keep the original order + id_list = [id for id in ids if id in final_ids] + return id_list def check_access_rule(self, cr, uid, ids, operation, context=None): """ Access rules of mail.message: diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index f873daff9c3..c5e28fe6fb0 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -1540,6 +1540,7 @@ openerp.mail = function (session) { 'show_compose_message': this.view.is_action_enabled('edit'), }); this.node.context = { + 'mail_read_set_read': true, // set messages as read in Chatter 'default_res_id': this.view.datarecord.id || false, 'default_model': this.view.model || false, }; diff --git a/addons/mail/tests/test_message_read.py b/addons/mail/tests/test_message_read.py index 46dd29a5431..fb195eaec2b 100644 --- a/addons/mail/tests/test_message_read.py +++ b/addons/mail/tests/test_message_read.py @@ -26,7 +26,8 @@ class test_mail_access_rights(TestMailBase): def test_00_message_read(self): """ Tests for message_read and expandables. """ - cr, uid, user_admin, group_pigs = self.cr, self.uid, self.user_admin, self.group_pigs + cr, uid, user_admin, user_raoul, group_pigs = self.cr, self.uid, self.user_admin, self.user_raoul, self.group_pigs + self.mail_group.message_subscribe_users(cr, uid, [group_pigs.id], [user_raoul.id]) pigs_domain = [('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)] # Data: create a discussion in Pigs (3 threads, with respectively 0, 4 and 4 answers) @@ -44,20 +45,32 @@ class test_mail_access_rights(TestMailBase): msg_ids = [msg_id10, msg_id9, msg_id8, msg_id7, msg_id6, msg_id5, msg_id4, msg_id3, msg_id2, msg_id1, msg_id0] ordered_msg_ids = [msg_id2, msg_id4, msg_id6, msg_id8, msg_id10, msg_id1, msg_id3, msg_id5, msg_id7, msg_id9, msg_id0] + # Test: raoul received notifications + raoul_notification_ids = self.mail_notification.search(cr, user_raoul.id, [('read', '=', False), ('message_id', 'in', msg_ids), ('partner_id', '=', user_raoul.partner_id.id)]) + self.assertEqual(len(raoul_notification_ids), 11, 'message_post: wrong number of produced notifications') + # Test: read some specific ids - read_msg_list = self.mail_message.message_read(cr, uid, ids=msg_ids[2:4], domain=[('body', 'like', 'dummy')]) + read_msg_list = self.mail_message.message_read(cr, user_raoul.id, ids=msg_ids[2:4], domain=[('body', 'like', 'dummy')], context={'mail_read_set_read': True}) read_msg_ids = [msg.get('id') for msg in read_msg_list] self.assertEqual(msg_ids[2:4], read_msg_ids, 'message_read with direct ids should read only the requested ids') + # Test: raoul notifications are read + raoul_notification_ids = self.mail_notification.search(cr, user_raoul.id, [('read', '=', False), ('message_id', 'in', msg_ids), ('partner_id', '=', user_raoul.partner_id.id)]) + self.assertEqual(len(raoul_notification_ids), 9, 'message_post: wrong number of produced and/or read notifications') + # Test: read messages of Pigs through a domain, being thread or not threaded - read_msg_list = self.mail_message.message_read(cr, uid, domain=pigs_domain, limit=200) + read_msg_list = self.mail_message.message_read(cr, user_raoul.id, domain=pigs_domain, limit=200) read_msg_ids = [msg.get('id') for msg in read_msg_list] self.assertEqual(msg_ids, read_msg_ids, 'message_read flat with domain on Pigs should equal all messages of Pigs') - read_msg_list = self.mail_message.message_read(cr, uid, domain=pigs_domain, limit=200, thread_level=1) + read_msg_list = self.mail_message.message_read(cr, user_raoul.id, domain=pigs_domain, limit=200, thread_level=1) read_msg_ids = [msg.get('id') for msg in read_msg_list] self.assertEqual(ordered_msg_ids, read_msg_ids, 'message_read threaded with domain on Pigs should equal all messages of Pigs, and sort them with newer thread first, last message last in thread') + # Test: raoul notifications did not change + raoul_notification_ids = self.mail_notification.search(cr, user_raoul.id, [('read', '=', False), ('message_id', 'in', msg_ids), ('partner_id', '=', user_raoul.partner_id.id)]) + self.assertEqual(len(raoul_notification_ids), 9, 'message_post: wrong number of produced and/or read notifications') + # ---------------------------------------- # CASE1: message_read with domain, threaded # We simulate an entire flow, using the expandables to test them @@ -80,14 +93,6 @@ class test_mail_access_rights(TestMailBase): elif msg.get('type') == 'expandable': new_msg_exp = msg - # #check notification For message readable or unread. - # notif_msg1_ids1 = self.mail_notification.search(cr, uid, [('partner_id', '=', user_bert.partner_id.id),('message_id', '=', message1.id)], context=context) - # notif_data1 = self.mail_notification.read(cr, uid, notif_msg1_ids1, ['read'])[0]['read'] - # # Test: Message1 are marked as read. - # self.assertTrue(notif_data1, 'Message1 are set as read for the user Bert that read it') - # #Pass key in context for unread message.. - # context.update({'default_model': 'mail.group', 'default_res_id': [self.group_pigs_id], 'mail_keep_unread': True}) - # Do: fetch new messages in first thread, domain from expandable self.assertIsNotNone(new_msg_exp, 'message_read on last Pigs message should have returned a new messages expandable') domain = new_msg_exp.get('domain', []) From b1274847338e98c54737ee4ff343b81f7dbdd554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 20 Dec 2012 15:35:27 +0100 Subject: [PATCH 08/18] [IMP] set messages read when viewing chatter: search only unread notifications. bzr revid: tde@openerp.com-20121220143527-y98r2hftskgb9e3g --- addons/mail/mail_message.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 207b46de5d5..1d248aadb6f 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -538,8 +538,8 @@ class mail_message(osv.Model): # if requested: mark messages as read if context and context.get('mail_read_set_read'): message_ids = [message.get('id') for message in message_list] - notif_ids = notification_obj.search(cr, uid, [('partner_id.user_ids', 'in', uid), ('message_id', 'in', message_ids)], context=context) - notification_obj.write(cr, uid, notif_ids, {'read': True}, context=context) + unread_notif_ids = notification_obj.search(cr, uid, [('read', '=', False), ('partner_id.user_ids', 'in', uid), ('message_id', 'in', message_ids)], context=context) + notification_obj.write(cr, uid, unread_notif_ids, {'read': True}, context=context) # get the child expandable messages for the tree self._message_read_dict_postprocess(cr, uid, message_list, message_tree, context=context) From de64985e8cf94edec1d4a2fb4cb7a3ea0234bc31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 20 Dec 2012 21:53:28 +0100 Subject: [PATCH 09/18] [IMP] mail_message: set_message_read and set_message_starred now have an argument to control the automatic notification creation. Chatter now calls set_message_read on received messages (on documents), to set them as read. This is therefore done independently of the message_read, to avoid writing in a read-based method. Added a mutex on the call on set_message_read, because of a recurrent concurrent accesses issue. bzr revid: tde@openerp.com-20121220205328-gws2j32dsitofu89 --- addons/mail/mail_message.py | 38 ++++++++++++-------------- addons/mail/static/src/js/mail.js | 17 ++++++++++-- addons/mail/tests/test_message_read.py | 8 +++--- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 1d248aadb6f..f6fbb25988b 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -224,23 +224,25 @@ class mail_message(osv.Model): # Notification API #------------------------------------------------------ - def set_message_read(self, cr, uid, msg_ids, read, context=None): + def set_message_read(self, cr, uid, msg_ids, read, create_missing=True, context=None): """ Set messages as (un)read. Technically, the notifications related to uid are set to (un)read. If for some msg_ids there are missing notifications (i.e. due to load more or thread parent fetching), they are created. :param bool read: set notification as (un)read + :param bool create_missing: create notifications for missing entries + (i.e. when acting on displayed messages not notified) """ notification_obj = self.pool.get('mail.notification') user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] - notif_ids = notification_obj.search(cr, uid, [ - ('partner_id', '=', user_pid), - ('message_id', 'in', msg_ids) - ], context=context) + domain = [('partner_id', '=', user_pid), ('message_id', 'in', msg_ids)] + if not create_missing: + domain += [('read', '=', not read)] + notif_ids = notification_obj.search(cr, uid, domain, context=context) # all message have notifications: already set them as (un)read - if len(notif_ids) == len(msg_ids): + if len(notif_ids) == len(msg_ids) or not create_missing: return notification_obj.write(cr, uid, notif_ids, {'read': read}, context=context) # some messages do not have notifications: find which one, create notification, update read status @@ -250,23 +252,23 @@ class mail_message(osv.Model): notification_obj.create(cr, uid, {'partner_id': user_pid, 'read': read, 'message_id': msg_id}, context=context) return notification_obj.write(cr, uid, notif_ids, {'read': read}, context=context) - def set_message_starred(self, cr, uid, msg_ids, starred, context=None): + def set_message_starred(self, cr, uid, msg_ids, starred, create_missing=True, context=None): """ Set messages as (un)starred. Technically, the notifications related - to uid are set to (un)starred. If for some msg_ids there are missing - notifications (i.e. due to load more or thread parent fetching), - they are created. + to uid are set to (un)starred. :param bool starred: set notification as (un)starred + :param bool create_missing: create notifications for missing entries + (i.e. when acting on displayed messages not notified) """ notification_obj = self.pool.get('mail.notification') user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] - notif_ids = notification_obj.search(cr, uid, [ - ('partner_id', '=', user_pid), - ('message_id', 'in', msg_ids) - ], context=context) + domain = [('partner_id', '=', user_pid), ('message_id', 'in', msg_ids)] + if not create_missing: + domain += [('starred', '=', not read)] + notif_ids = notification_obj.search(cr, uid, domain, context=context) # all message have notifications: already set them as (un)starred - if len(notif_ids) == len(msg_ids): + if len(notif_ids) == len(msg_ids) or not create_missing: notification_obj.write(cr, uid, notif_ids, {'starred': starred}, context=context) return starred @@ -535,12 +537,6 @@ class mail_message(osv.Model): parent_list = sorted(parent_list, key=lambda item: max([msg.get('id') for msg in item[1]]) if item[1] else item[0], reverse=True) message_list = [message for (key, msg_list) in parent_list for message in msg_list] - # if requested: mark messages as read - if context and context.get('mail_read_set_read'): - message_ids = [message.get('id') for message in message_list] - unread_notif_ids = notification_obj.search(cr, uid, [('read', '=', False), ('partner_id.user_ids', 'in', uid), ('message_id', 'in', message_ids)], context=context) - notification_obj.write(cr, uid, unread_notif_ids, {'read': True}, context=context) - # get the child expandable messages for the tree self._message_read_dict_postprocess(cr, uid, message_list, message_tree, context=context) self._message_read_add_expandables(cr, uid, message_list, message_tree, parent_tree, diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index c5e28fe6fb0..1765c351bb2 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -862,7 +862,7 @@ openerp.mail = function (session) { } var message_ids = _.map(messages, function (val) { return val.id; }); - this.ds_message.call('set_message_read', [message_ids, read_value, this.context]) + this.ds_message.call('set_message_read', [message_ids, read_value, true, this.context]) .then(function () { // apply modification _.each(messages, function (msg) { @@ -911,7 +911,7 @@ openerp.mail = function (session) { var self=this; var button = self.$('.oe_star:first'); - this.ds_message.call('set_message_starred', [[self.id], !self.is_favorite]) + this.ds_message.call('set_message_starred', [[self.id], !self.is_favorite, true]) .then(function (star) { self.is_favorite=star; if (self.is_favorite) { @@ -992,6 +992,7 @@ openerp.mail = function (session) { this.ds_thread = new session.web.DataSetSearch(this, this.context.default_model || 'mail.thread'); this.ds_message = new session.web.DataSetSearch(this, 'mail.message'); + this.render_mutex = new $.Mutex(); }, start: function () { @@ -1184,7 +1185,17 @@ openerp.mail = function (session) { (replace_context ? replace_context : this.context), // parent_id this.context.default_parent_id || undefined - ]).done(callback ? _.bind(callback, this, arguments) : this.proxy('switch_new_message')); + ]).done(callback ? _.bind(callback, this, arguments) : this.proxy('switch_new_message') + ).done(this.proxy('message_fetch_set_read')); + }, + + message_fetch_set_read: function (message_list) { + if (! this.context.mail_read_set_read) return; + this.render_mutex.exec(_.bind(function() { + msg_ids = _.pluck(message_list, 'id'); + return this.ds_message.call('set_message_read', [ + msg_ids, true, false, this.context]); + }, this)); }, /** diff --git a/addons/mail/tests/test_message_read.py b/addons/mail/tests/test_message_read.py index fb195eaec2b..3f20b38e55a 100644 --- a/addons/mail/tests/test_message_read.py +++ b/addons/mail/tests/test_message_read.py @@ -55,8 +55,8 @@ class test_mail_access_rights(TestMailBase): self.assertEqual(msg_ids[2:4], read_msg_ids, 'message_read with direct ids should read only the requested ids') # Test: raoul notifications are read - raoul_notification_ids = self.mail_notification.search(cr, user_raoul.id, [('read', '=', False), ('message_id', 'in', msg_ids), ('partner_id', '=', user_raoul.partner_id.id)]) - self.assertEqual(len(raoul_notification_ids), 9, 'message_post: wrong number of produced and/or read notifications') + # raoul_notification_ids = self.mail_notification.search(cr, user_raoul.id, [('read', '=', False), ('message_id', 'in', msg_ids), ('partner_id', '=', user_raoul.partner_id.id)]) + # self.assertEqual(len(raoul_notification_ids), 9, 'message_post: wrong number of produced and/or read notifications') # Test: read messages of Pigs through a domain, being thread or not threaded read_msg_list = self.mail_message.message_read(cr, user_raoul.id, domain=pigs_domain, limit=200) @@ -68,8 +68,8 @@ class test_mail_access_rights(TestMailBase): 'message_read threaded with domain on Pigs should equal all messages of Pigs, and sort them with newer thread first, last message last in thread') # Test: raoul notifications did not change - raoul_notification_ids = self.mail_notification.search(cr, user_raoul.id, [('read', '=', False), ('message_id', 'in', msg_ids), ('partner_id', '=', user_raoul.partner_id.id)]) - self.assertEqual(len(raoul_notification_ids), 9, 'message_post: wrong number of produced and/or read notifications') + # raoul_notification_ids = self.mail_notification.search(cr, user_raoul.id, [('read', '=', False), ('message_id', 'in', msg_ids), ('partner_id', '=', user_raoul.partner_id.id)]) + # self.assertEqual(len(raoul_notification_ids), 9, 'message_post: wrong number of produced and/or read notifications') # ---------------------------------------- # CASE1: message_read with domain, threaded From e97dc0ffd40caccc3dd8bdc0839e7d052f28344e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 20 Dec 2012 22:11:03 +0100 Subject: [PATCH 10/18] [IMP] mail.js: improved display of destination partners of a message. bzr revid: tde@openerp.com-20121220211103-5zjb6xclllgcyr8f --- addons/mail/static/src/js/mail.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 1765c351bb2..03d13a5605b 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -963,6 +963,7 @@ openerp.mail = function (session) { * use with browse, fetch... [O]= top parent */ init: function (parent, datasets, options) { + var self = this; this._super(parent, options); this.domain = options.domain || []; this.context = _.extend(options.context || {}); @@ -975,14 +976,15 @@ openerp.mail = function (session) { this.parent_message= parent.thread!= undefined ? parent : false ; // data of this thread - this.id = datasets.id || false, - this.last_id = datasets.last_id || false, - this.parent_id = datasets.parent_id || false, - - this.is_private = datasets.is_private || false, - this.author_id = datasets.author_id || false, - this.thread_level = (datasets.thread_level+1) || 0, - this.partner_ids = _.filter(datasets.partner_ids, function (partner) { return partner[0]!=datasets.author_id[0]; } ) + this.id = datasets.id || false; + this.last_id = datasets.last_id || false; + this.parent_id = datasets.parent_id || false; + this.is_private = datasets.is_private || false; + this.author_id = datasets.author_id || false; + this.thread_level = (datasets.thread_level+1) || 0; + this.partner_ids = datasets.partner_ids || []; + if (datasets.author_id) + this.partner_ids.push(datasets.author_id); this.messages = []; this.options.flat_mode = !!(this.options.display_indented_thread > this.thread_level ? this.options.display_indented_thread - this.thread_level : 0); From 0f62de1b2f713cfd3a0212bfa9e34c10e6749674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 20 Dec 2012 22:12:21 +0100 Subject: [PATCH 11/18] [FIX] Fixed commit about adding create_missing parameter: wrong var name. bzr revid: tde@openerp.com-20121220211221-fksj045ds3slrjvx --- addons/mail/mail_message.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index f6fbb25988b..b040aee9c6f 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -264,7 +264,7 @@ class mail_message(osv.Model): user_pid = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] domain = [('partner_id', '=', user_pid), ('message_id', 'in', msg_ids)] if not create_missing: - domain += [('starred', '=', not read)] + domain += [('starred', '=', not starred)] notif_ids = notification_obj.search(cr, uid, domain, context=context) # all message have notifications: already set them as (un)starred From b37450ba49c18ce7b1575915b863f8c21bf54330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 21 Dec 2012 10:59:02 +0100 Subject: [PATCH 12/18] [IMP] sale, purchase, invoice: automatically subscibe recipints of Send by email as document followers. bzr revid: tde@openerp.com-20121221095902-k2xk928po48cogdm --- addons/account/account_invoice.py | 3 ++- addons/mail/wizard/mail_compose_message.py | 3 +++ addons/purchase/purchase.py | 11 +++++------ addons/sale/sale.py | 4 +++- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/addons/account/account_invoice.py b/addons/account/account_invoice.py index 3defd82d0ac..6cc3b367925 100644 --- a/addons/account/account_invoice.py +++ b/addons/account/account_invoice.py @@ -1779,12 +1779,13 @@ class res_partner(osv.osv): return super(res_partner, self).copy(cr, uid, id, default, context) -class mail_compose_message(osv.osv): +class mail_compose_message(osv.Model): _inherit = 'mail.compose.message' def send_mail(self, cr, uid, ids, context=None): context = context or {} if context.get('default_model') == 'account.invoice' and context.get('default_res_id') and context.get('mark_invoice_as_sent'): + context = dict(context, mail_post_autofollow=True) self.pool.get('account.invoice').write(cr, uid, [context['default_res_id']], {'sent': True}, context=context) return super(mail_compose_message, self).send_mail(cr, uid, ids, context=context) diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index 44396e5d143..0062b5e01bd 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -214,6 +214,9 @@ class mail_compose_message(osv.TransientModel): new_attachments = email_dict.pop('attachments', []) post_values['attachments'] += new_attachments post_values.update(email_dict) + # automatically subscribe recipients if asked to + if context.get('mail_post_autofollow') and wizard.model and post_values.get('partner_ids'): + active_model_pool.message_subscribe(cr, uid, [res_id], [item[1] for item in post_values.get('partner_ids')], context=context) # post the message active_model_pool.message_post(cr, uid, [res_id], type='comment', subtype='mt_comment', context=context, **post_values) diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 95a952e243e..9aa3db887d2 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -1214,9 +1214,8 @@ class procurement_order(osv.osv): body = _("Draft Purchase Order created") self.message_post(cr, uid, [procurement.id], body=body, context=context) -procurement_order() -class mail_mail(osv.osv): +class mail_mail(osv.Model): _name = 'mail.mail' _inherit = 'mail.mail' @@ -1226,9 +1225,8 @@ class mail_mail(osv.osv): wf_service.trg_validate(uid, 'purchase.order', mail.res_id, 'send_rfq', cr) return super(mail_mail, self)._postprocess_sent_message(cr, uid, mail=mail, context=context) -mail_mail() -class product_template(osv.osv): +class product_template(osv.Model): _name = 'product.template' _inherit = 'product.template' _columns = { @@ -1238,13 +1236,14 @@ class product_template(osv.osv): 'purchase_ok': 1, } -product_template() -class mail_compose_message(osv.osv): +class mail_compose_message(osv.Model): _inherit = 'mail.compose.message' + def send_mail(self, cr, uid, ids, context=None): context = context or {} if context.get('default_model') == 'purchase.order' and context.get('default_res_id'): + context = dict(context, mail_post_autofollow=True) wf_service = netsvc.LocalService("workflow") wf_service.trg_validate(uid, 'purchase.order', context['default_res_id'], 'send_rfq', cr) return super(mail_compose_message, self).send_mail(cr, uid, ids, context=context) diff --git a/addons/sale/sale.py b/addons/sale/sale.py index cf68ee01672..a37b6e2280a 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -1010,11 +1010,13 @@ class sale_order_line(osv.osv): return super(sale_order_line, self).unlink(cr, uid, ids, context=context) -class mail_compose_message(osv.osv): +class mail_compose_message(osv.Model): _inherit = 'mail.compose.message' + def send_mail(self, cr, uid, ids, context=None): context = context or {} if context.get('default_model') == 'sale.order' and context.get('default_res_id') and context.get('mark_so_as_sent'): + context = dict(context, mail_post_autofollow=True) wf_service = netsvc.LocalService("workflow") wf_service.trg_validate(uid, 'sale.order', context['default_res_id'], 'quotation_sent', cr) return super(mail_compose_message, self).send_mail(cr, uid, ids, context=context) From c88008856e88ce9f50d6b0ebbc072aa24c079b92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 21 Dec 2012 11:03:52 +0100 Subject: [PATCH 13/18] [IMP] message_process: author of incoming emails that are partner are automatically subscribed to the created or updated document. bzr revid: tde@openerp.com-20121221100352-eraewn17t2ls831q --- addons/mail/mail_thread.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 48bdef508d0..d980f001814 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -446,7 +446,7 @@ class mail_thread(osv.AbstractModel): (msg['message_id'], model) # disabled subscriptions during message_new/update to avoid having the system user running the - # email gateway become a follower of all inbound messages + # email gateway become a follower of all inbound messages nosub_ctx = dict(context, mail_nosubscribe=True) if thread_id and hasattr(model_pool, 'message_update'): model_pool.message_update(cr, user_id, [thread_id], msg, context=nosub_ctx) @@ -457,6 +457,10 @@ class mail_thread(osv.AbstractModel): model_pool = self.pool.get('mail.thread') new_msg_id = model_pool.message_post_user_api(cr, uid, [thread_id], context=context, content_subtype='html', **msg) + # when posting an incoming email to a document: subscribe the author, if a partner, as follower + if model and thread_id and msg.get('author_id'): + model_pool.message_subscribe(cr, uid, [thread_id], [msg.get('author_id')], context=context) + if partner_ids: # postponed after message_post, because this is an external message and we don't want to create # duplicate emails due to notifications From e6a63fea3a7dd251145647887e3365fd8dcb6e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 21 Dec 2012 12:17:55 +0100 Subject: [PATCH 14/18] [FIX] mail: tests: fixed mock of gateway. bzr revid: tde@openerp.com-20121221111755-63q6w4pkvkx0lvcf --- addons/mail/tests/test_mail_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/tests/test_mail_base.py b/addons/mail/tests/test_mail_base.py index 527375644df..fb53220ef1f 100644 --- a/addons/mail/tests/test_mail_base.py +++ b/addons/mail/tests/test_mail_base.py @@ -25,7 +25,7 @@ from openerp.tests import common class TestMailBase(common.TransactionCase): def _mock_smtp_gateway(self, *args, **kwargs): - return True + return args[2]['Message-Id'] def _init_mock_build_email(self): self._build_email_args_list = [] From 19efa31b51cfbff87d48436a9e083d1f173c5f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 21 Dec 2012 12:39:27 +0100 Subject: [PATCH 15/18] [FIX] mail: attachments were not send by email. bzr revid: tde@openerp.com-20121221113927-4q90f0in645gorj9 --- addons/mail/mail_thread.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index ae6532c0cbc..296c212e0fb 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -828,7 +828,7 @@ class mail_thread(osv.AbstractModel): mail_message = self.pool.get('mail.message') model = context.get('thread_model', self._name) if thread_id else False - attachment_ids = [] + attachment_ids = kwargs.pop('attachment_ids', []) for name, content in attachments: if isinstance(content, unicode): content = content.encode('utf-8') @@ -903,7 +903,6 @@ class mail_thread(osv.AbstractModel): - extra_email: [ 'Fabien ', 'al@openerp.com' ] """ ir_attachment = self.pool.get('ir.attachment') - mail_message = self.pool.get('mail.message') # 1. Pre-processing: body, partner_ids, type and subtype if content_subtype == 'plaintext': @@ -926,11 +925,7 @@ class mail_thread(osv.AbstractModel): message_type = kwargs.pop('type', 'comment') message_subtype = kwargs.pop('subtype', 'mail.mt_comment') - # 2. Post message - new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=message_type, - subtype=message_subtype, parent_id=parent_id, context=context, partner_ids=partner_ids, **kwargs) - - # 3. Post-processing + # 2. Pre-processing: free attachments linked to the model # HACK TDE FIXME: Chatter: attachments linked to the document (not done JS-side), load the message if attachment_ids: # TDE FIXME (?): when posting a private message, we use mail.thread as a model @@ -946,7 +941,13 @@ class mail_thread(osv.AbstractModel): if filtered_attachment_ids: if thread_id and model: ir_attachment.write(cr, SUPERUSER_ID, attachment_ids, {'res_model': model, 'res_id': thread_id}, context=context) - mail_message.write(cr, SUPERUSER_ID, [new_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]}, context=context) + else: + attachment_ids = [] + + # 3. Post message + new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=message_type, + subtype=message_subtype, parent_id=parent_id, attachment_ids=[(4, id) for id in attachment_ids], + context=context, partner_ids=partner_ids, **kwargs) return new_message_id From b4e1e32f0abb60f75b02be83e91bbcf32f3aa0e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 21 Dec 2012 12:53:15 +0100 Subject: [PATCH 16/18] [FIX] portal: fixed various mail_mail records created without specifying the 'type' field; however this may conflict with the context holdign default_type (i.e. opportunity), leading to type values not in the selection field. bzr revid: tde@openerp.com-20121221115315-qni401mszwrkpvmj --- addons/portal/wizard/portal_wizard.py | 1 + addons/portal_sale/portal_sale.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/addons/portal/wizard/portal_wizard.py b/addons/portal/wizard/portal_wizard.py index e88c68379ab..e3047cd5edb 100644 --- a/addons/portal/wizard/portal_wizard.py +++ b/addons/portal/wizard/portal_wizard.py @@ -212,6 +212,7 @@ class wizard_user(osv.osv_memory): 'subject': _(WELCOME_EMAIL_SUBJECT) % data, 'body_html': '
%s
' % (_(WELCOME_EMAIL_BODY) % data), 'state': 'outgoing', + 'type': 'email', } mail_id = mail_mail.create(cr, uid, mail_values, context=this_context) return mail_mail.send(cr, uid, [mail_id], context=this_context) diff --git a/addons/portal_sale/portal_sale.py b/addons/portal_sale/portal_sale.py index 3556fd5ca0e..d4d5b64cea3 100644 --- a/addons/portal_sale/portal_sale.py +++ b/addons/portal_sale/portal_sale.py @@ -68,6 +68,7 @@ class sale_order(osv.Model): 'subject': 'Invitation to follow %s' % document.name_get()[0][1], 'body_html': 'You have been invited to follow %s' % document.name_get()[0][1], 'auto_delete': True, + 'type': 'email', } mail_obj = self.pool.get('mail.mail') mail_id = mail_obj.create(cr, uid, mail_values, context=context) @@ -128,6 +129,7 @@ class account_invoice(osv.Model): 'subject': 'Invitation to follow %s' % document.name_get()[0][1], 'body_html': 'You have been invited to follow %s' % document.name_get()[0][1], 'auto_delete': True, + 'type': 'email', } mail_obj = self.pool.get('mail.mail') mail_id = mail_obj.create(cr, uid, mail_values, context=context) From 692cea303901391550db36705b3a731726ed4043 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Fri, 21 Dec 2012 13:06:31 +0100 Subject: [PATCH 17/18] Removed default image on partners, use default one in the kanban view if false bzr revid: nicolas.vanhoren@openerp.com-20121221120631-2uugaiexqanwbi00 --- openerp/addons/base/res/res_partner.py | 12 ++++++--- openerp/addons/base/res/res_partner_view.xml | 27 +++++++++++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 65bcf18653e..b35db73b1f4 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -187,6 +187,12 @@ class res_partner(osv.osv, format_address): def _set_image(self, cr, uid, id, name, value, args, context=None): return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context) + def _has_image(self, cr, uid, ids, name, args, context=None): + result = {} + for obj in self.browse(cr, uid, ids, context=context): + result[obj.id] = obj.image != False + return result + _order = "name" _columns = { 'name': fields.char('Name', size=128, required=True, select=True), @@ -253,6 +259,7 @@ class res_partner(osv.osv, format_address): help="Small-sized image of this contact. It is automatically "\ "resized as a 64x64px image, with aspect ratio preserved. "\ "Use this field anywhere a small image is required."), + 'has_image': fields.function(_has_image, type="boolean"), 'company_id': fields.many2one('res.company', 'Company', select=1), 'color': fields.integer('Color Index'), 'user_ids': fields.one2many('res.users', 'partner_id', 'Users'), @@ -297,7 +304,7 @@ class res_partner(osv.osv, format_address): 'is_company': False, 'type': 'default', 'use_parent_address': True, - 'image': lambda self, cr, uid, ctx: self._get_default_image(cr, uid, ctx.get('default_is_company', False), ctx), + 'image': False, } def copy(self, cr, uid, id, default=None, context=None): @@ -308,8 +315,7 @@ class res_partner(osv.osv, format_address): return super(res_partner, self).copy(cr, uid, id, default, context) def onchange_type(self, cr, uid, ids, is_company, context=None): - # get value as for an onchange on the image - value = tools.image_get_resized_images(self._get_default_image(cr, uid, is_company, context), return_big=True, return_medium=False, return_small=False) + value = {} value['title'] = False if is_company: value['parent_id'] = False diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml index bd518c08aab..d1a803ce2d8 100644 --- a/openerp/addons/base/res/res_partner_view.xml +++ b/openerp/addons/base/res/res_partner_view.xml @@ -196,13 +196,13 @@ - + @@ -210,7 +210,17 @@ X
- + + + + + + + + + + +
@@ -331,11 +341,22 @@ +
- + + + + + + + + + + +

From 149e5b3da5266cd31f922862fd9f5f7af879ca72 Mon Sep 17 00:00:00 2001 From: "vta vta@openerp.com" <> Date: Fri, 21 Dec 2012 13:48:40 +0100 Subject: [PATCH 18/18] [FIX] portal_hr_employees ACL bzr revid: vta@openerp.com-20121221124840-og5945c111b3vons --- addons/portal_hr_employees/security/ir.model.access.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/portal_hr_employees/security/ir.model.access.csv b/addons/portal_hr_employees/security/ir.model.access.csv index 914649ef1fe..f8a1eb74c35 100644 --- a/addons/portal_hr_employees/security/ir.model.access.csv +++ b/addons/portal_hr_employees/security/ir.model.access.csv @@ -1,3 +1,3 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_hr_employee_user,hr.employee user,hr.model_hr_employee,portal.group_portal,1,0,0,0 -access_hr_employee_user,hr.employee user,hr.model_hr_employee,portal.group_anonymous,1,0,0,0 +access_hr_employee_portal,hr.employee user,hr.model_hr_employee,portal.group_portal,1,0,0,0 +access_hr_employee_anonymous,hr.employee user,hr.model_hr_employee,portal.group_anonymous,1,0,0,0