[IMP] mail: added auto_follow mechanism on fields like 'user_id'. mail.thread defines a basic heuristic to find those tracked fields: fields called 'user_id', linking to res_users, that are tracked. This allows to automatically subscribe the responsible of main models in OpenERP, like opportunity, task, issue, applicant. This revision also sets some subtypes as not followed by default to avoid leaking information (for example when changing state of a recruitment with the applicant automatically added as follower).

bzr revid: tde@openerp.com-20130130145834-e5lr8h36xozavr7f
This commit is contained in:
Thibault Delavallée 2013-01-30 15:58:34 +01:00
commit 0dc0b1c08a
10 changed files with 59 additions and 15 deletions

View File

@ -155,11 +155,13 @@
<record id="mt_invoice_validated" model="mail.message.subtype">
<field name="name">Validated</field>
<field name="res_model">account.invoice</field>
<field name="default" eval="False"/>
<field name="description">Invoice validated</field>
</record>
<record id="mt_invoice_paid" model="mail.message.subtype">
<field name="name">Paid</field>
<field name="res_model">account.invoice</field>
<field name="default" eval="False"/>
<field name="description">Invoice paid</field>
</record>
</data>

View File

@ -17,6 +17,7 @@
<record id="mt_voucher_state_change" model="mail.message.subtype">
<field name="name">Status Change</field>
<field name="res_model">account.voucher</field>
<field name="default" eval="False"/>
<field name="description">Status changed</field>
</record>

View File

@ -6,16 +6,19 @@
<record id="mt_account_pending" model="mail.message.subtype">
<field name="name">Contract to Renew</field>
<field name="res_model">account.analytic.account</field>
<field name="default" eval="False"/>
<field name="description">Contract pending</field>
</record>
<record id="mt_account_closed" model="mail.message.subtype">
<field name="name">Contract Finished</field>
<field name="res_model">account.analytic.account</field>
<field name="default" eval="False"/>
<field name="description">Contract closed</field>
</record>
<record id="mt_account_opened" model="mail.message.subtype">
<field name="name">Contract Opened</field>
<field name="res_model">account.analytic.account</field>
<field name="default" eval="False"/>
<field name="description">Contract opened</field>
</record>

View File

@ -171,11 +171,13 @@
<record id="mt_lead_stage" model="mail.message.subtype">
<field name="name">Stage Changed</field>
<field name="res_model">crm.lead</field>
<field name="default" eval="False"/>
<field name="description">Stage changed</field>
</record>
<record id="mt_lead_won" model="mail.message.subtype">
<field name="name">Opportunity Won</field>
<field name="res_model">crm.lead</field>
<field name="default" eval="False"/>
<field name="description">Opportunity won</field>
</record>
<record id="mt_lead_lost" model="mail.message.subtype">

View File

@ -470,11 +470,13 @@
<record id="mt_stage_changed" model="mail.message.subtype">
<field name="name">Stage Changed</field>
<field name="res_model">hr.applicant</field>
<field name="default" eval="False"/>
<field name="description">Stage changed</field>
</record>
<record id="mt_applicant_hired" model="mail.message.subtype">
<field name="name">Applicant Hired</field>
<field name="res_model">hr.applicant</field>
<field name="default" eval="False"/>
<field name="description">Applicant hired</field>
</record>
<record id="mt_applicant_refused" model="mail.message.subtype">

View File

@ -243,7 +243,7 @@ class mail_thread(osv.AbstractModel):
# subscribe uid unless asked not to
if not context.get('mail_create_nosubscribe'):
self.message_subscribe_users(cr, uid, [thread_id], [uid], context=context)
self.message_subscribe_from_parent(cr, uid, [thread_id], values.keys(), context=context)
self.message_auto_subscribe(cr, uid, [thread_id], values.keys(), context=context)
# automatic logging unless asked not to (mainly for various testing purpose)
if not context.get('mail_create_nolog'):
@ -261,7 +261,7 @@ class mail_thread(osv.AbstractModel):
# Perform write, update followers
result = super(mail_thread, self).write(cr, uid, ids, values, context=context)
self.message_subscribe_from_parent(cr, uid, ids, values.keys(), context=context)
self.message_auto_subscribe(cr, uid, ids, values.keys(), context=context)
# Perform the tracking
if tracked_fields:
@ -1069,7 +1069,24 @@ class mail_thread(osv.AbstractModel):
self.check_access_rights(cr, uid, 'write')
return self.write(cr, SUPERUSER_ID, ids, {'message_follower_ids': [(3, pid) for pid in partner_ids]}, context=context)
def message_subscribe_from_parent(self, cr, uid, ids, updated_fields, context=None):
def _message_get_auto_subscribe_fields(self, cr, uid, updated_fields, auto_follow_fields=['user_id'], context=None):
""" Returns the list of relational fields linking to res.users that should
trigger an auto subscribe. The default list checks for the fields
- called 'user_id'
- linking to res.users
- with track_visibility set
In OpenERP V7, this is sufficent for all major addon such as opportunity,
project, issue, recruitment, sale.
Override this method if a custom behavior is needed about fields
that automatically subscribe users.
"""
user_field_lst = []
for name, column_info in self._all_columns.items():
if name in auto_follow_fields and name in updated_fields and getattr(column_info.column, 'track_visibility', False) and column_info.column._obj == 'res.users':
user_field_lst.append(name)
return user_field_lst
def message_auto_subscribe(self, cr, uid, ids, updated_fields, context=None):
"""
1. fetch project subtype related to task (parent_id.res_model = 'project.task')
2. for each project subtype: subscribe the follower to the task
@ -1077,13 +1094,16 @@ class mail_thread(osv.AbstractModel):
subtype_obj = self.pool.get('mail.message.subtype')
follower_obj = self.pool.get('mail.followers')
# fetch auto_follow_fields
user_field_lst = self._message_get_auto_subscribe_fields(cr, uid, updated_fields, context=context)
# fetch related record subtypes
related_subtype_ids = subtype_obj.search(cr, uid, ['|', ('res_model', '=', False), ('parent_id.res_model', '=', self._name)], context=context)
subtypes = subtype_obj.browse(cr, uid, related_subtype_ids, context=context)
default_subtypes = [subtype for subtype in subtypes if subtype.res_model == False]
related_subtypes = [subtype for subtype in subtypes if subtype.res_model != False]
relation_fields = set([subtype.relation_field for subtype in subtypes if subtype.relation_field != False])
if not related_subtypes or not any(relation in updated_fields for relation in relation_fields):
if (not related_subtypes or not any(relation in updated_fields for relation in relation_fields)) and not user_field_lst:
return True
for record in self.browse(cr, uid, ids, context=context):
@ -1105,20 +1125,24 @@ class mail_thread(osv.AbstractModel):
for follower in follower_obj.browse(cr, SUPERUSER_ID, follower_ids, context=context):
new_followers.setdefault(follower.partner_id.id, set()).add(subtype.parent_id.id)
if not parent_res_id or not parent_model:
continue
if parent_res_id and parent_model:
for subtype in default_subtypes:
follower_ids = follower_obj.search(cr, SUPERUSER_ID, [
('res_model', '=', parent_model),
('res_id', '=', parent_res_id),
('subtype_ids', 'in', [subtype.id])
], context=context)
for follower in follower_obj.browse(cr, SUPERUSER_ID, follower_ids, context=context):
new_followers.setdefault(follower.partner_id.id, set()).add(subtype.id)
for subtype in default_subtypes:
follower_ids = follower_obj.search(cr, SUPERUSER_ID, [
('res_model', '=', parent_model),
('res_id', '=', parent_res_id),
('subtype_ids', 'in', [subtype.id])
], context=context)
for follower in follower_obj.browse(cr, SUPERUSER_ID, follower_ids, context=context):
new_followers.setdefault(follower.partner_id.id, set()).add(subtype.id)
# add followers coming from res.users relational fields that are tracked
user_ids = [getattr(record, name).id for name in user_field_lst if getattr(record, name)]
for partner_id in [user.partner_id.id for user in self.pool.get('res.users').browse(cr, SUPERUSER_ID, user_ids, context=context)]:
new_followers.setdefault(partner_id, None)
for pid, subtypes in new_followers.items():
self.message_subscribe(cr, uid, [record.id], [pid], list(subtypes), context=context)
subtypes = list(subtypes) if subtypes is not None else None
self.message_subscribe(cr, uid, [record.id], [pid], subtypes, context=context)
return True
#------------------------------------------------------

View File

@ -94,16 +94,19 @@
<record id="mt_task_blocked" model="mail.message.subtype">
<field name="name">Task Blocked</field>
<field name="res_model">project.task</field>
<field name="default" eval="False"/>
<field name="description">Task blocked</field>
</record>
<record id="mt_task_closed" model="mail.message.subtype">
<field name="name">Task Done</field>
<field name="res_model">project.task</field>
<field name="default" eval="False"/>
<field name="description">Task closed</field>
</record>
<record id="mt_task_stage" model="mail.message.subtype">
<field name="name">Stage Changed</field>
<field name="res_model">project.task</field>
<field name="default" eval="False"/>
<field name="description">Stage changed</field>
</record>
<!-- Project-related subtypes for messaging / Chatter -->

View File

@ -59,16 +59,19 @@ Access all issues from the top Project menu, and access the issues of a specific
<record id="mt_issue_blocked" model="mail.message.subtype">
<field name="name">Issue Blocked</field>
<field name="res_model">project.issue</field>
<field name="default" eval="False"/>
<field name="description">Issue blocked</field>
</record>
<record id="mt_issue_closed" model="mail.message.subtype">
<field name="name">Issue Closed</field>
<field name="res_model">project.issue</field>
<field name="default" eval="False"/>
<field name="description">Issue closed</field>
</record>
<record id="mt_issue_stage" model="mail.message.subtype">
<field name="name">Stage Changed</field>
<field name="res_model">project.issue</field>
<field name="default" eval="False"/>
<field name="description">Stage changed</field>
</record>
<!-- Project-related subtypes for messaging / Chatter -->

View File

@ -52,10 +52,12 @@
<!-- Purchase-related subtypes for messaging / Chatter -->
<record id="mt_rfq_confirmed" model="mail.message.subtype">
<field name="name">RFQ Confirmed</field>
<field name="default" eval="False"/>
<field name="res_model">purchase.order</field>
</record>
<record id="mt_rfq_approved" model="mail.message.subtype">
<field name="name">RFQ Approved</field>
<field name="default" eval="False"/>
<field name="res_model">purchase.order</field>
</record>

View File

@ -48,11 +48,13 @@
<record id="mt_order_sent" model="mail.message.subtype">
<field name="name">Quotation send</field>
<field name="res_model">sale.order</field>
<field name="default" eval="False"/>
<field name="description">Quotation send</field>
</record>
<record id="mt_order_confirmed" model="mail.message.subtype">
<field name="name">Sales Order Confirmed</field>
<field name="res_model">sale.order</field>
<field name="default" eval="False"/>
<field name="description">Quotation confirmed</field>
</record>