[IMP] sale order line invisible type
[odoo/odoo.git] / addons / mail / doc / mail_openchatter_howto.rst
1
2 How to use OpenChatter in my addon
3 ===================================
4
5 Running example
6 ++++++++++++++++
7
8 A small my_task model will be used as example to explain how to use the OpenChatter feature. Being simple, it has only the following fields :
9
10  - a name
11  - a task responsible
12  - a related project
13
14 ::
15
16   class my_task(osv.osv):
17     _name = "my.task"
18     _description = "My Task"
19     _columns = {
20       'name': fields.char('Name', required=True, size=64),
21       'user_id':fields.many2one('res.users', string='Responsible',
22         ondelete='cascade', required=True, select=1),
23       'project_id':fields.many2one('project.project', string='Related project',
24         ondelete='cascade', required=True, select=1),
25     }
26
27
28 Two-lines feature integration
29 ++++++++++++++++++++++++++++++
30
31 Make your module inheriting from the ``mail.thread`` class.
32
33 ::
34
35   class my_task(osv.osv):
36     _name = "my.task"
37     _description = "My Task"
38     # inherit from mail.thread allows the use of OpenChatter
39     _inherit = ['mail.thread']
40
41 Use the thread viewer widget inside your form view by using the mail_thread widget on the message_ids field inherited from mail.thread.
42
43 ::
44
45   <record model="ir.ui.view" id="my_task_form_view">
46     <field name="name">My Task</field>
47     <field name="model">my.task</field>
48     <field name="priority">1</field>
49     <field name="arch" type="xml">
50       <form>
51       [...]
52       <field name="message_ids" colspan="4" widget="mail_thread" nolabel="1"/>
53       </form>
54     </field>
55   </record>
56
57 Send notifications
58 +++++++++++++++++++
59
60 When sending a notification is required in your workflow or business logic, use the ``message_append_note`` method. This method is a shortcut to the ``message_append`` method that takes all ``mail.message`` fields as arguments. This latter method calls ``message_create`` that
61
62  - creates the message
63  - parses the body to find users you want to push the message to (finding and parsing ``@login`` in the message body)
64  - pushes a notification to users following the document and requested users of the latetr step
65
66 You should therefore not worry about subscriptions or anything else than sending the notification. Here is a small example of sending a notification when the ``do_something`` method is called : 
67
68 ::
69
70   def do_something(self, cr, uid, ids, context=None):
71     [...]
72     self.do_something_send_note(cr, uid, ids, context=context)
73     [...]
74     return res
75
76   def do_something_send_note(self, cr, uid, ids, context=None):
77     self.message_append_note(cr, uid, ids, _('My subject'),
78     _("has received a <b>notification</b> and is happy for it."), context=context)
79
80 Notifications guidelines
81 +++++++++++++++++++++++++
82
83 Here are a few guidelines that you should keep in mind during the addition of system notifications :
84
85  - avoid unnecessary content; if a message has no interest, do not implement it
86  - use short sentences
87  - do not include the document name, as it is managed by the thread widget
88  - use a simple and clean style
89
90    - html tags are supported: use <b> or <em> mainly
91    - put main word(s) in bold
92    - avoid fancy styles that will break the OpenERP look and feel
93  - create a separate method for sending your notification
94
95    - use a method name like ``original_method_name_send_note``, that allow to easily spot notification methods in the code
96
97 Subscription management
98 ++++++++++++++++++++++++
99
100 There are a few default subscription tricks that you should know before playing with subscription:
101
102  - users that click on 'follow' follow the document. An entry in ``mail.subscription`` is created.
103  - users that click on 'unfollow' are no longer followers to the document. The related entry in ``mail.subscription`` is created.
104  - users that create or update a document automatically follow it. An entry in ``mail.subscription`` is created.
105
106 If you want to override this default behavior, you should avoid doing it manualle. You should instead override the ``message_get_subscribers`` method from mail.thread. The default implementation looks in the ``mail.suscription`` table for entries matching ``user_id=uid, res_model=self._name, res_id=current_record_id``. You can add subscribers by overriding the ``message_get_subscribers`` and adding user ids to the returned list. This means that they will be considered as followers even if they do not have an entry in the mail.subscription table.
107
108 As an exemple, let us say that you want to automatically add the my_task responsible along with the project manager to the list of followers. The method could look like:
109
110 ::
111
112   def message_get_subscribers(self, cr, uid, ids, context=None):
113     # get the followers from the mail.subscription table
114     sub_ids = self.message_get_subscribers_ids(cr, uid, ids, context=context);
115     # add the employee and its manager if specified to the subscribed users
116     for obj in self.browse(cr, uid, ids, context=context):
117       if obj.user_id:
118         sub_ids.append(obj.user_id)
119       if obj.project_id and obj.project_id.user_id:
120         sub_ids.append(obj.project_id.user_id)
121     return self.pool.get('res.users').read(cr, uid, sub_ids, context=context)
122
123 This method has the advantage of being able to implement a particular behavior with as few code addition as possible. Moreover, when changing the task responsible of the project manager, the subscribers are always correct. This allows to avoid to implement complex corner cases that could obfuscate the code.
124
125 The drawback of this method is that it is no longer possible to those subscribers to unfollow a document. Indeed, as user ids are added directly in a list in ``message_get_subscribers``, it is not possible to unsubscribe to a document. However, this drawback is mitigated by
126
127  - only important users shoudl be added using this method. Important users should not unsubscribe from their documents.
128  - users can hide the notifications on their Wall
129
130 Messages display management
131 ++++++++++++++++++++++++++++
132
133 By default, the mail_thread widget shows all messages related to the current document beside the document, in the History and comments section. However, you may want to display other messages in the widget. For example, the OpenChatter on res.users model shows
134
135  - messages related to the user, as usual (messages with ``model = res.users, res_id = current_document_id``)
136  - messages directly pushed to this user (containing @login)
137
138 The best way to direct the messages that will be displayed in the OpenChatter widget is to override the ``message_load`` method. For example, the following method fetches messages as usual, but also fetches messages linked to the task project that contain the task name. Please refer to the API for more details about the arguments.
139
140 ::
141
142   def message_load(self, cr, uid, ids, limit=100, offset=0, domain=[], ascent=False, root_ids=[False], context=None):
143     msg_obj = self.pool.get('mail.message')
144     for my_task in self.browse(cr, uid, ids, context=context):
145       # search as usual messages related to the current document
146       msg_ids += msg_obj.search(cr, uid, ['|', '&', ('res_id', '=', my_task.id), ('model', '=', self._name),
147         # add: search in the current task project messages
148         '&', '&', ('res_id', '=', my_task.project_id.id), ('model', '=', 'project.project'),
149         # ... containing the task name
150         '|', ('body_text', 'like', '%s' % (my_task.name)), ('body_html', 'like', '%s' % (my_task.name))
151         ] + domain, limit=limit, offset=offset, context=context)
152     # if asked: add ancestor ids to have complete threads
153     if (ascent): msg_ids = self._message_add_ancestor_ids(cr, uid, ids, msg_ids, root_ids, context=context)
154     return msg_obj.read(cr, uid, msg_ids, context=context)