2011-07-22 16:34:57 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
##############################################################################
|
|
|
|
#
|
|
|
|
# OpenERP, Open Source Management Solution
|
2012-03-13 13:59:49 +00:00
|
|
|
# Copyright (C) 2010-today OpenERP SA (<http://www.openerp.com>)
|
2011-07-22 16:34:57 +00:00
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU Affero General Public License as
|
|
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
|
|
# License, or (at your option) any later version
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU Affero General Public License for more details
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
|
|
#
|
|
|
|
##############################################################################
|
|
|
|
|
|
|
|
import logging
|
2012-09-05 15:53:19 +00:00
|
|
|
import tools
|
|
|
|
|
2011-07-22 16:34:57 +00:00
|
|
|
from email.header import decode_header
|
2012-09-05 15:53:19 +00:00
|
|
|
from operator import itemgetter
|
2012-08-23 18:54:43 +00:00
|
|
|
from osv import osv, fields
|
2011-07-22 16:34:57 +00:00
|
|
|
|
2012-06-22 06:48:54 +00:00
|
|
|
_logger = logging.getLogger(__name__)
|
2011-07-22 16:34:57 +00:00
|
|
|
|
2012-07-06 09:41:41 +00:00
|
|
|
""" Some tools for parsing / creating email fields """
|
2011-07-22 16:34:57 +00:00
|
|
|
def decode(text):
|
|
|
|
"""Returns unicode() string conversion of the the given encoded smtp header text"""
|
|
|
|
if text:
|
|
|
|
text = decode_header(text.replace('\r', ''))
|
|
|
|
return ''.join([tools.ustr(x[0], x[1]) for x in text])
|
2012-08-20 11:31:50 +00:00
|
|
|
|
2012-05-08 13:56:00 +00:00
|
|
|
class mail_message(osv.Model):
|
2012-08-31 09:01:20 +00:00
|
|
|
""" Messages model: system notification (replacing res.log notifications),
|
|
|
|
comments (OpenChatter discussion) and incoming emails. """
|
2011-07-22 16:34:57 +00:00
|
|
|
_name = 'mail.message'
|
2012-08-15 17:08:22 +00:00
|
|
|
_description = 'Message'
|
2012-08-20 19:10:58 +00:00
|
|
|
_inherit = ['ir.needaction_mixin']
|
2012-08-15 17:08:22 +00:00
|
|
|
_order = 'id desc'
|
2011-07-22 16:34:57 +00:00
|
|
|
|
2012-08-27 09:42:28 +00:00
|
|
|
_message_read_limit = 10
|
|
|
|
_message_record_name_length = 18
|
|
|
|
|
|
|
|
def _shorten_name(self, name):
|
2012-09-05 15:53:19 +00:00
|
|
|
if len(name) <= (self._message_record_name_length + 3):
|
2012-08-27 09:42:28 +00:00
|
|
|
return name
|
2012-08-28 17:39:01 +00:00
|
|
|
return name[:self._message_record_name_length] + '...'
|
2012-08-27 09:42:28 +00:00
|
|
|
|
2012-08-28 09:53:23 +00:00
|
|
|
def _get_record_name(self, cr, uid, ids, name, arg, context=None):
|
2012-08-27 09:42:28 +00:00
|
|
|
""" Return the related document name, using get_name. """
|
2012-08-15 17:08:22 +00:00
|
|
|
result = dict.fromkeys(ids, '')
|
|
|
|
for message in self.browse(cr, uid, ids, context=context):
|
|
|
|
if not message.model or not message.res_id:
|
|
|
|
continue
|
2012-08-27 09:42:28 +00:00
|
|
|
result[message.id] = self._shorten_name(self.pool.get(message.model).name_get(cr, uid, [message.res_id], context=context)[0][1])
|
2012-08-15 17:08:22 +00:00
|
|
|
return result
|
|
|
|
|
2012-08-28 09:53:23 +00:00
|
|
|
def _get_unread(self, cr, uid, ids, name, arg, context=None):
|
|
|
|
""" Compute if the message is unread by the current user. """
|
2012-08-28 15:02:44 +00:00
|
|
|
res = dict((id, {'unread': False}) for id in ids)
|
2012-08-28 09:53:23 +00:00
|
|
|
partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
|
|
|
notif_obj = self.pool.get('mail.notification')
|
|
|
|
notif_ids = notif_obj.search(cr, uid, [
|
|
|
|
('partner_id', 'in', [partner_id]),
|
|
|
|
('message_id', 'in', ids),
|
|
|
|
('read', '=', False)
|
|
|
|
], context=context)
|
|
|
|
for notif in notif_obj.browse(cr, uid, notif_ids, context=context):
|
|
|
|
res[notif.message_id.id]['unread'] = True
|
|
|
|
return res
|
|
|
|
|
|
|
|
def _search_unread(self, cr, uid, obj, name, domain, context=None):
|
2012-09-05 15:53:19 +00:00
|
|
|
""" Search for messages unread by the current user. Condition is
|
2012-08-31 09:01:20 +00:00
|
|
|
inversed because we search unread message on a read column. """
|
2012-08-31 11:23:53 +00:00
|
|
|
if domain[0][2]:
|
|
|
|
read_cond = '(read = false or read is null)'
|
|
|
|
else:
|
|
|
|
read_cond = 'read = true'
|
2012-08-28 09:53:23 +00:00
|
|
|
partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
2012-08-31 11:23:53 +00:00
|
|
|
cr.execute("SELECT message_id FROM mail_notification "\
|
|
|
|
"WHERE partner_id = %%s AND %s" % read_cond,
|
|
|
|
(partner_id,))
|
2012-08-31 09:01:20 +00:00
|
|
|
return [('id', 'in', [r[0] for r in cr.fetchall()])]
|
2012-08-28 09:53:23 +00:00
|
|
|
|
2012-08-15 17:08:22 +00:00
|
|
|
def name_get(self, cr, uid, ids, context=None):
|
2012-08-10 14:43:39 +00:00
|
|
|
# name_get may receive int id instead of an id list
|
|
|
|
if isinstance(ids, (int, long)):
|
|
|
|
ids = [ids]
|
2012-08-15 17:08:22 +00:00
|
|
|
res = []
|
|
|
|
for message in self.browse(cr, uid, ids, context=context):
|
2012-08-27 09:42:28 +00:00
|
|
|
name = '%s: %s' % (message.subject or '', message.body or '')
|
|
|
|
res.append((message.id, self._shorten_name(name.lstrip(' :'))))
|
2012-08-15 17:08:22 +00:00
|
|
|
return res
|
|
|
|
|
2011-07-22 16:34:57 +00:00
|
|
|
_columns = {
|
2012-04-02 16:24:25 +00:00
|
|
|
'type': fields.selection([
|
2012-08-31 09:01:20 +00:00
|
|
|
('email', 'Email'),
|
2012-04-02 16:24:25 +00:00
|
|
|
('comment', 'Comment'),
|
|
|
|
('notification', 'System notification'),
|
2012-07-20 09:25:45 +00:00
|
|
|
], 'Type',
|
|
|
|
help="Message type: email for email message, notification for system "\
|
2012-08-23 18:54:43 +00:00
|
|
|
"message, comment for other messages such as user replies"),
|
2012-08-15 17:08:22 +00:00
|
|
|
'author_id': fields.many2one('res.partner', 'Author', required=True),
|
2012-08-23 18:54:43 +00:00
|
|
|
'partner_ids': fields.many2many('res.partner', 'mail_notification', 'message_id', 'partner_id', 'Recipients'),
|
|
|
|
'attachment_ids': fields.many2many('ir.attachment', 'message_attachment_rel',
|
|
|
|
'message_id', 'attachment_id', 'Attachments'),
|
|
|
|
'parent_id': fields.many2one('mail.message', 'Parent Message', select=True, ondelete='set null', help="Initial thread message."),
|
2012-08-15 20:01:26 +00:00
|
|
|
'child_ids': fields.one2many('mail.message', 'parent_id', 'Child Messages'),
|
2012-08-15 17:08:22 +00:00
|
|
|
'model': fields.char('Related Document Model', size=128, select=1),
|
|
|
|
'res_id': fields.integer('Related Document ID', select=1),
|
2012-08-28 09:53:23 +00:00
|
|
|
'record_name': fields.function(_get_record_name, type='string',
|
2012-08-15 17:08:22 +00:00
|
|
|
string='Message Record Name',
|
|
|
|
help="Name get of the related document."),
|
2012-08-20 11:31:50 +00:00
|
|
|
'notification_ids': fields.one2many('mail.notification', 'message_id', 'Notifications'),
|
2012-08-23 18:54:43 +00:00
|
|
|
'subject': fields.char('Subject'),
|
2012-08-15 17:08:22 +00:00
|
|
|
'date': fields.datetime('Date'),
|
2012-08-23 18:54:43 +00:00
|
|
|
'message_id': fields.char('Message-Id', help='Message unique identifier', select=1, readonly=1),
|
2012-08-29 15:00:02 +00:00
|
|
|
'body': fields.html('Contents', help='Automatically sanitized HTML contents'),
|
2012-08-28 09:53:23 +00:00
|
|
|
'unread': fields.function(_get_unread, fnct_search=_search_unread,
|
|
|
|
type='boolean', string='Unread',
|
|
|
|
help='Functional field to search for unread messages linked to uid'),
|
2011-07-22 16:34:57 +00:00
|
|
|
}
|
2012-08-21 12:10:30 +00:00
|
|
|
|
2012-08-28 09:53:23 +00:00
|
|
|
def _needaction_domain_get(self, cr, uid, context=None):
|
2012-08-22 13:37:23 +00:00
|
|
|
if self._needaction:
|
2012-08-28 09:53:23 +00:00
|
|
|
return [('unread', '=', True)]
|
2012-08-22 13:37:23 +00:00
|
|
|
return []
|
|
|
|
|
2012-08-28 09:53:23 +00:00
|
|
|
def _get_default_author(self, cr, uid, context=None):
|
2012-08-17 11:19:36 +00:00
|
|
|
return self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
|
|
|
|
2011-08-23 17:58:09 +00:00
|
|
|
_defaults = {
|
2012-04-03 17:34:49 +00:00
|
|
|
'type': 'email',
|
2012-08-16 09:26:16 +00:00
|
|
|
'date': lambda *a: fields.datetime.now(),
|
2012-09-05 15:53:19 +00:00
|
|
|
'author_id': lambda self, cr, uid, ctx={}: self._get_default_author(cr, uid, ctx),
|
2012-09-04 11:54:16 +00:00
|
|
|
'body': '',
|
2011-08-23 17:58:09 +00:00
|
|
|
}
|
2012-08-15 17:08:22 +00:00
|
|
|
|
2012-08-20 09:06:36 +00:00
|
|
|
#------------------------------------------------------
|
|
|
|
# Message loading for web interface
|
|
|
|
#------------------------------------------------------
|
|
|
|
|
2012-08-27 14:47:53 +00:00
|
|
|
def _message_dict_get(self, cr, uid, msg, context=None):
|
|
|
|
""" Return a dict representation of the message browse record. """
|
|
|
|
attachment_ids = self.pool.get('ir.attachment').name_get(cr, uid, [x.id for x in msg.attachment_ids], context=context)
|
|
|
|
author_id = self.pool.get('res.partner').name_get(cr, uid, [msg.author_id.id], context=context)[0]
|
|
|
|
author_user_id = self.pool.get('res.users').name_get(cr, uid, [msg.author_id.user_ids[0].id], context=context)[0]
|
2012-08-20 10:57:49 +00:00
|
|
|
partner_ids = self.pool.get('res.partner').name_get(cr, uid, [x.id for x in msg.partner_ids], context=context)
|
2012-08-20 09:39:22 +00:00
|
|
|
return {
|
|
|
|
'id': msg.id,
|
|
|
|
'type': msg.type,
|
2012-08-27 14:47:53 +00:00
|
|
|
'attachment_ids': attachment_ids,
|
2012-08-20 09:39:22 +00:00
|
|
|
'body': msg.body,
|
|
|
|
'model': msg.model,
|
|
|
|
'res_id': msg.res_id,
|
|
|
|
'record_name': msg.record_name,
|
|
|
|
'subject': msg.subject,
|
|
|
|
'date': msg.date,
|
2012-08-27 14:47:53 +00:00
|
|
|
'author_id': author_id,
|
|
|
|
'author_user_id': author_user_id,
|
2012-08-20 10:57:49 +00:00
|
|
|
'partner_ids': partner_ids,
|
2012-08-27 14:47:53 +00:00
|
|
|
'child_ids': [],
|
2012-08-20 09:39:22 +00:00
|
|
|
}
|
|
|
|
|
2012-08-28 14:26:34 +00:00
|
|
|
def message_read_tree_flatten(self, cr, uid, messages, current_level, level, context=None):
|
|
|
|
""" Given a tree with several roots of following structure :
|
2012-08-31 13:15:03 +00:00
|
|
|
[ {'id': 1, 'child_ids': [
|
|
|
|
{'id': 11, 'child_ids': [...] },],
|
|
|
|
{...} ]
|
2012-09-05 15:53:19 +00:00
|
|
|
Flatten it to have a maximum number of levels, 0 being flat and
|
|
|
|
sort messages in a level according to a key of the messages.
|
2012-08-28 14:26:34 +00:00
|
|
|
Perform the flattening at leafs if above the maximum depth, then get
|
|
|
|
back in the tree.
|
2012-09-05 15:53:19 +00:00
|
|
|
:param context: ``sort_key``: key for sorting (id by default)
|
|
|
|
:param context: ``sort_reverse``: reverser order for sorting (True by default)
|
2012-08-28 14:26:34 +00:00
|
|
|
"""
|
|
|
|
def _flatten(msg_dict):
|
|
|
|
""" from {'id': x, 'child_ids': [{child1}, {child2}]}
|
|
|
|
get [{'id': x, 'child_ids': []}, {child1}, {child2}]
|
|
|
|
"""
|
|
|
|
child_ids = msg_dict.pop('child_ids', [])
|
|
|
|
msg_dict['child_ids'] = []
|
|
|
|
return [msg_dict] + child_ids
|
2012-09-05 15:53:19 +00:00
|
|
|
# return sorted([msg_dict] + child_ids, key=itemgetter('id'), reverse=True)
|
|
|
|
context = context or {}
|
2012-08-28 14:26:34 +00:00
|
|
|
# Depth-first flattening
|
|
|
|
for message in messages:
|
2012-08-31 14:37:07 +00:00
|
|
|
if message.get('type') == 'expandable':
|
2012-08-31 13:15:03 +00:00
|
|
|
continue
|
2012-09-05 15:53:19 +00:00
|
|
|
message['child_ids'] = self.message_read_tree_flatten(cr, uid, message['child_ids'], current_level + 1, level, context=context)
|
2012-08-28 14:26:34 +00:00
|
|
|
# Flatten if above maximum depth
|
|
|
|
if current_level < level:
|
2012-09-05 15:53:19 +00:00
|
|
|
return_list = messages
|
|
|
|
else:
|
|
|
|
return_list = []
|
|
|
|
for message in messages:
|
|
|
|
for flat_message in _flatten(message):
|
|
|
|
return_list.append(flat_message)
|
|
|
|
return sorted(return_list, key=itemgetter(context.get('sort_key', 'id')), reverse=context.get('sort_reverse', True))
|
2012-08-28 14:26:34 +00:00
|
|
|
|
2012-08-27 16:22:37 +00:00
|
|
|
def message_read(self, cr, uid, ids=False, domain=[], thread_level=0, limit=None, context=None):
|
2012-08-31 14:37:07 +00:00
|
|
|
""" If IDs are provided, fetch these records. Otherwise use the domain
|
|
|
|
to fetch the matching records.
|
|
|
|
After having fetched the records provided by IDs, it will fetch the
|
|
|
|
parents to have well-formed threads.
|
|
|
|
:return list: list of trees of messages
|
2012-08-20 11:31:50 +00:00
|
|
|
"""
|
2012-08-27 16:22:37 +00:00
|
|
|
limit = limit or self._message_read_limit
|
|
|
|
context = context or {}
|
2012-08-31 14:37:07 +00:00
|
|
|
if not ids:
|
2012-08-27 16:22:37 +00:00
|
|
|
ids = self.search(cr, uid, domain, context=context, limit=limit)
|
|
|
|
messages = self.browse(cr, uid, ids, context=context)
|
|
|
|
|
|
|
|
result = []
|
2012-08-20 09:39:22 +00:00
|
|
|
tree = {} # key: ID, value: record
|
|
|
|
for msg in messages:
|
2012-09-05 15:53:19 +00:00
|
|
|
if len(result) < (limit - 1):
|
2012-08-27 16:22:37 +00:00
|
|
|
record = self._message_dict_get(cr, uid, msg, context=context)
|
|
|
|
if thread_level and msg.parent_id:
|
|
|
|
while msg.parent_id:
|
|
|
|
if msg.parent_id.id in tree:
|
|
|
|
record_parent = tree[msg.parent_id.id]
|
|
|
|
else:
|
|
|
|
record_parent = self._message_dict_get(cr, uid, msg.parent_id, context=context)
|
2012-08-28 13:13:11 +00:00
|
|
|
if msg.parent_id.parent_id:
|
2012-08-27 16:22:37 +00:00
|
|
|
tree[msg.parent_id.id] = record_parent
|
2012-08-28 13:13:11 +00:00
|
|
|
if record['id'] not in [x['id'] for x in record_parent['child_ids']]:
|
|
|
|
record_parent['child_ids'].append(record)
|
2012-08-27 16:22:37 +00:00
|
|
|
record = record_parent
|
|
|
|
msg = msg.parent_id
|
|
|
|
if msg.id not in tree:
|
|
|
|
result.append(record)
|
|
|
|
tree[msg.id] = record
|
|
|
|
else:
|
|
|
|
result.append({
|
2012-08-27 15:03:03 +00:00
|
|
|
'type': 'expandable',
|
2012-09-05 15:53:19 +00:00
|
|
|
'domain': [('id', '<=', msg.id)] + domain,
|
2012-08-27 15:03:03 +00:00
|
|
|
'context': context,
|
2012-09-05 23:49:19 +00:00
|
|
|
'thread_level': thread_level, # should be improve accodting to level of records
|
|
|
|
'id': -1,
|
2012-08-27 15:03:03 +00:00
|
|
|
})
|
2012-08-27 16:22:37 +00:00
|
|
|
break
|
2012-08-28 14:26:34 +00:00
|
|
|
|
|
|
|
# Flatten the result
|
2012-08-31 13:15:03 +00:00
|
|
|
if thread_level > 0:
|
|
|
|
result = self.message_read_tree_flatten(cr, uid, result, 0, thread_level, context=context)
|
2012-08-27 16:22:37 +00:00
|
|
|
return result
|
2012-08-20 09:06:36 +00:00
|
|
|
|
2012-02-02 09:48:45 +00:00
|
|
|
#------------------------------------------------------
|
2012-06-25 13:42:53 +00:00
|
|
|
# Email api
|
2012-02-02 09:48:45 +00:00
|
|
|
#------------------------------------------------------
|
2012-08-15 17:08:22 +00:00
|
|
|
|
2011-07-22 16:34:57 +00:00
|
|
|
def init(self, cr):
|
|
|
|
cr.execute("""SELECT indexname FROM pg_indexes WHERE indexname = 'mail_message_model_res_id_idx'""")
|
|
|
|
if not cr.fetchone():
|
|
|
|
cr.execute("""CREATE INDEX mail_message_model_res_id_idx ON mail_message (model, res_id)""")
|
|
|
|
|
2012-08-31 09:01:20 +00:00
|
|
|
def check_access_rule(self, cr, uid, ids, operation, context=None):
|
|
|
|
""" mail.message access rule check
|
|
|
|
- message received (a notification exists) -> ok
|
|
|
|
- check rules of related document if exists
|
|
|
|
- fallback on normal mail.message check """
|
2012-05-08 13:56:00 +00:00
|
|
|
if isinstance(ids, (int, long)):
|
|
|
|
ids = [ids]
|
2012-08-15 20:01:26 +00:00
|
|
|
|
|
|
|
# check messages for which you have a notification
|
2012-08-31 09:01:20 +00:00
|
|
|
partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id
|
2012-08-15 20:01:26 +00:00
|
|
|
not_obj = self.pool.get('mail.notification')
|
|
|
|
not_ids = not_obj.search(cr, uid, [
|
|
|
|
('partner_id', '=', partner_id),
|
|
|
|
('message_id', 'in', ids),
|
|
|
|
], context=context)
|
2012-08-31 09:01:20 +00:00
|
|
|
notified_ids = [notification.message_id.id for notification in not_obj.browse(cr, uid, not_ids, context=context)
|
|
|
|
if notification.message_id.id in ids]
|
|
|
|
|
|
|
|
# check messages linked to an existing document
|
|
|
|
model_record_ids = {}
|
|
|
|
document_ids = []
|
|
|
|
cr.execute('SELECT DISTINCT id, model, res_id FROM mail_message WHERE id = ANY (%s)', (ids,))
|
|
|
|
for id, rmod, rid in cr.fetchall():
|
2012-05-08 13:56:00 +00:00
|
|
|
if not (rmod and rid):
|
|
|
|
continue
|
2012-08-31 09:01:20 +00:00
|
|
|
document_ids.append(id)
|
2012-09-05 15:53:19 +00:00
|
|
|
model_record_ids.setdefault(rmod, set()).add(rid)
|
2012-08-31 09:01:20 +00:00
|
|
|
for model, mids in model_record_ids.items():
|
|
|
|
model_obj = self.pool.get(model)
|
|
|
|
mids = model_obj.exists(cr, uid, mids)
|
|
|
|
model_obj.check_access_rights(cr, uid, operation)
|
|
|
|
model_obj.check_access_rule(cr, uid, mids, operation, context=context)
|
|
|
|
|
|
|
|
# fall back on classic operation for other ids
|
|
|
|
other_ids = set(ids).difference(set(notified_ids), set(document_ids))
|
|
|
|
super(mail_message, self).check_access_rule(cr, uid, other_ids, operation, context=None)
|
2012-08-15 17:08:22 +00:00
|
|
|
|
2012-05-08 13:56:00 +00:00
|
|
|
def create(self, cr, uid, values, context=None):
|
2012-08-28 17:39:01 +00:00
|
|
|
if not values.get('message_id') and values.get('res_id') and values.get('model'):
|
2012-09-05 15:53:19 +00:00
|
|
|
values['message_id'] = tools.generate_tracking_message_id('%(model)s-%(res_id)s' % values)
|
2012-08-15 13:36:43 +00:00
|
|
|
newid = super(mail_message, self).create(cr, uid, values, context)
|
2012-08-23 18:06:48 +00:00
|
|
|
self.notify(cr, uid, newid, context=context)
|
2012-08-15 13:36:43 +00:00
|
|
|
return newid
|
2012-05-08 13:56:00 +00:00
|
|
|
|
2012-09-05 15:19:50 +00:00
|
|
|
def unlink(self, cr, uid, ids, context=None):
|
|
|
|
# cascade-delete attachments that are directly attached to the message (should only happen
|
|
|
|
# for mail.messages that act as parent for a standalone mail.mail record.
|
|
|
|
attachments_to_delete = []
|
|
|
|
for mail in self.browse(cr, uid, ids, context=context):
|
|
|
|
for attach in mail.attachment_ids:
|
|
|
|
if attach.res_model == 'mail.message' and attach.res_id == mail.id:
|
|
|
|
attachments_to_delete.append(attach.id)
|
|
|
|
if attachments_to_delete:
|
|
|
|
self.pool.get('ir.attachment').unlink(cr, uid, attachments_to_delete, context=context)
|
|
|
|
return super(mail_message,self).unlink(cr, uid, ids, context=context)
|
|
|
|
|
2012-08-23 18:06:48 +00:00
|
|
|
def notify(self, cr, uid, newid, context=None):
|
|
|
|
""" Add the related record followers to the destination partner_ids.
|
|
|
|
Call mail_notification.notify to manage the email sending
|
|
|
|
"""
|
|
|
|
message = self.browse(cr, uid, newid, context=context)
|
2012-08-30 12:21:12 +00:00
|
|
|
partners_to_notify = set([])
|
2012-08-23 18:06:48 +00:00
|
|
|
# add all partner_ids of the message
|
|
|
|
if message.partner_ids:
|
2012-08-30 12:21:12 +00:00
|
|
|
partners_to_notify |= set(partner.id for partner in message.partner_ids)
|
|
|
|
# add all followers and set add them in partner_ids
|
2012-08-23 18:06:48 +00:00
|
|
|
if message.model and message.res_id:
|
2012-08-30 12:21:12 +00:00
|
|
|
record = self.pool.get(message.model).browse(cr, uid, message.res_id, context=context)
|
|
|
|
extra_notified = set(partner.id for partner in record.message_follower_ids)
|
|
|
|
missing_notified = extra_notified - partners_to_notify
|
|
|
|
if missing_notified:
|
|
|
|
message.write({'partner_ids': [(4, p_id) for p_id in missing_notified]})
|
|
|
|
partners_to_notify |= extra_notified
|
|
|
|
self.pool.get('mail.notification').notify(cr, uid, list(partners_to_notify), newid, context=context)
|
2012-08-23 18:06:48 +00:00
|
|
|
|
2011-08-23 17:58:09 +00:00
|
|
|
def copy(self, cr, uid, id, default=None, context=None):
|
|
|
|
"""Overridden to avoid duplicating fields that are unique to each email"""
|
|
|
|
if default is None:
|
|
|
|
default = {}
|
2012-08-15 18:44:03 +00:00
|
|
|
default.update(message_id=False, headers=False)
|
2012-09-05 15:53:19 +00:00
|
|
|
return super(mail_message, self).copy(cr, uid, id, default=default, context=context)
|