From 3657e4bd821e60544880985a5d48a5bc4419d803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 31 Jan 2012 16:50:00 +0100 Subject: [PATCH 001/691] [ADD] Added empty files for mail_group and mail_group views. Added css file for kanban view. Modified init and openerp files accordingly. bzr revid: tde@openerp.com-20120131155000-cmzd88d0rkso8sl1 --- addons/mail/__init__.py | 1 + addons/mail/__openerp__.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/addons/mail/__init__.py b/addons/mail/__init__.py index 4787883ef9c..c7fffb3a338 100644 --- a/addons/mail/__init__.py +++ b/addons/mail/__init__.py @@ -21,6 +21,7 @@ import mail_message import mail_thread +import mail_group import res_partner import wizard diff --git a/addons/mail/__openerp__.py b/addons/mail/__openerp__.py index 8085d301364..5e52e103852 100644 --- a/addons/mail/__openerp__.py +++ b/addons/mail/__openerp__.py @@ -58,6 +58,7 @@ The main features are: 'data': [ "wizard/mail_compose_message_view.xml", "mail_message_view.xml", + "mail_group_view.xml", "mail_thread_view.xml", "res_partner_view.xml", 'security/ir.model.access.csv', @@ -67,5 +68,6 @@ The main features are: 'auto_install': False, 'certificate': '001056784984222247309', 'images': ['images/customer_history.jpeg','images/messages_form.jpeg','images/messages_list.jpeg'], + 'css': ['static/src/css/mail_group.css'], } # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From a0a89fd37b24553776fa451466a922e727915571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 31 Jan 2012 16:52:57 +0100 Subject: [PATCH 002/691] [ADD] Really added files I was pretending to add in previous revision bzr revid: tde@openerp.com-20120131155257-skq6lu8g0mptm19h --- addons/mail/mail_group.py | 20 +++++++ addons/mail/mail_group_view.xml | 4 ++ addons/mail/static/src/css/mail_group.css | 68 +++++++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 addons/mail/mail_group.py create mode 100644 addons/mail/mail_group_view.xml create mode 100644 addons/mail/static/src/css/mail_group.css diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py new file mode 100644 index 00000000000..5dfeb073de6 --- /dev/null +++ b/addons/mail/mail_group.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2010-2011 OpenERP SA () +# +# 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 +# +############################################################################## \ No newline at end of file diff --git a/addons/mail/mail_group_view.xml b/addons/mail/mail_group_view.xml new file mode 100644 index 00000000000..b2839b2cc0a --- /dev/null +++ b/addons/mail/mail_group_view.xml @@ -0,0 +1,4 @@ + + + + diff --git a/addons/mail/static/src/css/mail_group.css b/addons/mail/static/src/css/mail_group.css new file mode 100644 index 00000000000..a65f766210e --- /dev/null +++ b/addons/mail/static/src/css/mail_group.css @@ -0,0 +1,68 @@ +.oe_group_vignette { + padding: 8px 0; + min-height: 100px; +} + +.oe_group_image, .oe_group_details { + display: inline-block; + vertical-align: top; +} + +.oe_group_image { + width: 100px; + height: 100px; + text-align: center; + overflow: hidden; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + -o-border-radius: 3px; + -ms-border-radius: 3px; + border-radius: 3px; + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); + -o-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); + -box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); +} + +.oe_group_picture { + width: 100px; + height: auto; + clip: rect(10px, 100px, 110px, 0px); +} + +.oe_group_picture_wide { + height: 100px; + width: auto; + clip: rect(0px, 115px, 100px, 15px); +} + +.oe_group_details { + width: 220px; + font-size: 13px; + padding: 2px 5px; + color: #4c4c4c; + min-height: 120px; +} + +.oe_group_details h4 { + margin: 0; + font-size: 13px; +} + +.oe_group_details h4 a { + color: #4c4c4c; +} + +.oe_group_details h4 a:hover { + text-decoration: underline; +} + +.oe_group_details ul { + margin: 3px 0 5px; + padding: 0; + list-style: none; +} + +.oe_group_details li { + margin: 2px 0; +} From f4551851fd7a3905782b4e81b81878d867cb2ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 31 Jan 2012 16:54:12 +0100 Subject: [PATCH 003/691] [IMP] Added group and subscription models. Added subscription mechanism when searching for tweets. Added views. bzr revid: tde@openerp.com-20120131155412-r16jr1nhwd9k4srv --- addons/mail/mail_group.py | 132 +++++++++++++++++++++++- addons/mail/mail_group_view.xml | 176 +++++++++++++++++++++++++++++++- addons/mail/mail_message.py | 81 ++++++++++++++- 3 files changed, 384 insertions(+), 5 deletions(-) diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py index 5dfeb073de6..996f9f174ae 100644 --- a/addons/mail/mail_group.py +++ b/addons/mail/mail_group.py @@ -17,4 +17,134 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see # -############################################################################## \ No newline at end of file +############################################################################## + +import tools +from osv import osv +from osv import fields +from tools.translate import _ + +class mail_group(osv.osv): + """ + A mail group is a collection of users sharing messages. Mail groups are different from user groups + because they don't have a specific field holding users. Group users are users that follow + the mail group, using the subscription/follow mechanism of Chatter. + """ + + _name = 'mail.group' + _inherits = {'res.groups': 'group_id'} + + def action_group_join(self, cr, uid, ids, context={}): + sub_obj = self.pool.get('mail.subscription') + menu_values = {'res_model': 'mail.group', 'user_id': uid} + for id in ids: + menu_values['res_id'] = id + sub_id = sub_obj.create(cr, uid, menu_values, context=context) + + for group in self.browse(cr, uid, ids, context): + self.write(cr, uid, group.id, { + 'users': [(4, uid)] + }) + + return True + + _columns = { + 'group_id': fields.many2one('res.groups', required=True, ondelete='cascade', + string='Group', + help='The group extended by this portal'), + #'name': fields.char('Name', size=64, required=True), + 'description': fields.text('Description'), + 'responsible_id': fields.many2one('res.users', string='Responsible', + ondelete='set null', required=True), + 'public': fields.boolean('Public', help='This group is visible by non members') + } + + _defaults = { + 'public': True, + } + + + def create(self, cr, uid, values, context=None): + """ extend create() to automatically create a menu for the group """ + if context is None: context = {} + # create group + group_id = super(mail_group, self).create(cr, uid, values, context) + # create menu + self._create_menu(cr, uid, [group_id], context) + return group_id + + def _create_menu(self, cr, uid, ids, context=None): + """ create a menu for the given groups """ + menu_obj = self.pool.get('ir.ui.menu') + ir_data = self.pool.get('ir.model.data') + act_win_obj = self.pool.get('ir.actions.act_window') + menu_root = self._get_res_xml_id(cr, uid, 'mail', 'mg_groups') + + for group in self.browse(cr, uid, ids, context): + # create an ir.action.act_window action + act_values = { + 'name': '%s' % group.name, + 'res_model': 'mail.message', + 'domain': '["&", ("res_model", "=", "mail.group"), ("res_id", "=", %s)]' % group.id, + } + act_id = act_win_obj.create(cr, uid, act_values, context) + # create a menuitem under 'mail.mg_groups' + menu_values = { + 'name': _('%s') % group.name, + 'parent_id': menu_root, + 'action': 'ir.actions.act_window,%s' % (act_id), + 'groups_id': [(6, 0, [group.group_id.id])], + } + menu_id = menu_obj.create(cr, uid, menu_values, context) + # create data + data_values = { + 'name': _('%s') % group.name, + 'model': 'ir.ui.menu', + 'module': 'portal', + 'res_id': menu_id, + 'noupdate': 'True'} + data_id = ir_data.create(cr, uid, data_values, context) + return True + + def _assign_menu(self, cr, uid, ids, context=None): + """ assign groups (ids) menu to the users joigning the groups""" + user_obj = self.pool.get('res.users') + for p in self.browse(cr, uid, ids, context): + # user menu action = portal menu action if set in portal + if p.menu_action_id: + user_ids = [u.id for u in p.users if u.id != 1] + user_values = {'menu_id': p.menu_action_id.id} + user_obj.write(cr, uid, user_ids, user_values, context) + + def _get_res_xml_id(self, cr, uid, module, xml_id): + """ return the resource id associated to the given xml_id """ + data_obj = self.pool.get('ir.model.data') + data_id = data_obj._get_id(cr, uid, module, xml_id) + return data_obj.browse(cr, uid, data_id).res_id + + +mail_group() + + +class mail_subscription(osv.osv): + """ + mail_subscription holds the data related to the follow mechanism inside OpenERP. + A subscription can be of following: + - res_model: model of the followed objects + - res_id: ID of resource OR + - res_domain: a domain filtering followed objects + """ + + _name = 'mail.subscription' + _rec_name = 'id' + _columns = { + 'res_model': fields.char('Related Document model', size=128, select=1), + 'res_id': fields.integer('Related Document ID', select=1), + 'res_domain': fields.char('res_domain', size=256), + 'user_id': fields.integer('Related User ID', select=1), + } + + _defaults = { + } + +mail_subscription() diff --git a/addons/mail/mail_group_view.xml b/addons/mail/mail_group_view.xml index b2839b2cc0a..3532eed5871 100644 --- a/addons/mail/mail_group_view.xml +++ b/addons/mail/mail_group_view.xml @@ -1,4 +1,178 @@ + - + + + mail.message.tree_tweet + mail.message + tree + 15 + + + + + + + + + + + + mail.message.form_tweet + mail.message + form + 15 + +
+ + + + + + + + + + + + +
+ + + + mail.message.search_tweet + mail.message + search + + + + + + + + + + mail.group.kanban + mail.group + kanban + + + + + +
+
+ + prout +
+
+

+
    +
  • +
  • Join
  • +
  • Joined
  • +
+
+ +
+
+
+
+
+
+ + + + mail.group.form + mail.group + form + + +
+ + + + + + + + + + + + + +
+ + + + Groups + mail.group + form + kanban,tree,form + + + + Messages + mail.message + form + tree,form + {'filter_search': True, 'tree_view_ref': 'mail.view_tweet_tree', 'form_view_ref': 'mail.view_tweet_form'} + + + + + Messages + mail.message + form + tree,form + {'filter_search': True, 'tree_view_ref': 'mail.view_tweet_tree', 'form_view_ref': 'mail.view_tweet_form'} + + [('user_id', '=', uid)] + + + + Subscriptions + mail.subscription + form + tree,form + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 1693397f6fa..825e3f3c7c6 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -71,8 +71,8 @@ class mail_message_common(osv.osv_memory): _rec_name = 'subject' _columns = { 'subject': fields.char('Subject', size=512, required=True), - 'model': fields.char('Related Document model', size=128, select=1, readonly=1), - 'res_id': fields.integer('Related Document ID', select=1, readonly=1), + 'model': fields.char('Related Document model', size=128, select=1), # was rfeadonly + 'res_id': fields.integer('Related Document ID', select=1), # was rfeadonly 'date': fields.datetime('Date'), 'email_from': fields.char('From', size=128, help='Message sender, taken from user preferences. If empty, this is not a mail but a message.'), 'email_to': fields.char('To', size=256, help='Message recipients'), @@ -163,7 +163,7 @@ class mail_message(osv.osv): _columns = { 'partner_id': fields.many2one('res.partner', 'Related partner'), - 'user_id': fields.many2one('res.users', 'Related user', readonly=1), + #'user_id': fields.many2one('res.users', 'Related user', readonly=1), 'attachment_ids': fields.many2many('ir.attachment', 'message_attachment_rel', 'message_id', 'attachment_id', 'Attachments'), 'display_text': fields.function(_get_display_text, method=True, type='text', size="512", string='Display Text'), 'mail_server_id': fields.many2one('ir.mail_server', 'Outgoing mail server', readonly=1), @@ -176,12 +176,87 @@ class mail_message(osv.osv): ], 'State', readonly=True), 'auto_delete': fields.boolean('Auto Delete', help="Permanently delete this email after sending it, to save space"), 'original': fields.binary('Original', help="Original version of the message, as it was sent on the network", readonly=1), + # tde add/modif + 'user_id': fields.many2one('res.users', 'Related user', readonly=1), + 'type': fields.selection([ + ('tweet', 'Tweet'), + ('status', 'Status'), + ], 'Type'), + 'need_action': fields.boolean('Need action'), } _defaults = { 'state': 'received', } + # thib add + def create(self, cr, uid, vals, context=None): + print vals + return super(mail_message, self).create(cr, uid, vals, context) + + def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False): + if not context or not context.has_key('filter_search'): + return super(mail_message, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count) + + # get subscriptions + sub_obj = self.pool.get('mail.subscription') + sub_ids = sub_obj.search(cr, uid, [('user_id', '=', uid)]) + subs = sub_obj.browse(cr, uid, sub_ids) + + # stock tweets to find + res_model_ids_dict = {} + res_model_all_list = [] + + # check all subscriptions + for sub in subs: + if sub.res_model and sub.res_id == 0 and sub.res_domain == False: + print "s-1" + if sub.res_model not in res_model_all_list: + res_model_all_list.append(sub.res_model) + elif sub.res_model and sub.res_id: + print "s-2" + if res_model_ids_dict.has_key(sub.res_model): + res_model_ids_dict[sub.res_model].append(sub.res_id) + else: + res_model_ids_dict[sub.res_model] = [sub.res_id] + elif sub.res_model and sub.res_domain: + print "s-3" + res_obj = self.pool.get(sub.res_model) + print sub.res_domain + #res_ids = res_obj.search(cr, uid, [('id', 'in', [1,2])]) + res_ids = res_obj.search(cr, uid, eval(sub.res_domain)) + if res_model_ids_dict.has_key(sub.res_model): + res_model_ids_dict[sub.res_model] += res_ids + else: + res_model_ids_dict[sub.res_model] = res_ids + print 'cacaprout' + else: + print 'erreur !!!' + print sub + + # add fully-followed domains + args.append('|') + args.append(['model', 'in', res_model_all_list]) + + # add partially-followed domains + for x in range(0, len(res_model_ids_dict.keys())-1): + args.append('|') + + for res_model in res_model_ids_dict.keys(): + if res_model not in res_model_all_list: + args.append('&') + args.append(['model', '=', res_model]) + args.append(['res_id', 'in', res_model_ids_dict[res_model]]) + + if context and context.has_key('filter_search'): + pass + else: + args = [] + print args + return super(mail_message, self).search(cr, uid, args, offset=offset, limit=limit,order=order, context=context, count=count) + + # end thib add + def init(self, cr): cr.execute("""SELECT indexname FROM pg_indexes WHERE indexname = 'mail_message_model_res_id_idx'""") if not cr.fetchone(): From b15ec8334bc641877e96957a064ca3b435248429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 31 Jan 2012 16:57:48 +0100 Subject: [PATCH 004/691] [FIX] Fixed missing fields for search. bzr revid: tde@openerp.com-20120131155748-1ossao3j32wd8bal --- addons/mail/mail_group_view.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/mail/mail_group_view.xml b/addons/mail/mail_group_view.xml index 3532eed5871..755583cc136 100644 --- a/addons/mail/mail_group_view.xml +++ b/addons/mail/mail_group_view.xml @@ -13,6 +13,8 @@ + + From 2107ef2017ffa97b2029b2fb682895be4ff9d08b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 1 Feb 2012 12:02:34 +0100 Subject: [PATCH 005/691] [FIX] Wrong field name in message tree view bzr revid: tde@openerp.com-20120201110234-a3vkrrtp70bc7wob --- addons/mail/mail_group_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/mail_group_view.xml b/addons/mail/mail_group_view.xml index 755583cc136..d6b852a2cbe 100644 --- a/addons/mail/mail_group_view.xml +++ b/addons/mail/mail_group_view.xml @@ -13,7 +13,7 @@ - + From 991d9b784399ab0efa602dfba5f6e5beee445356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 1 Feb 2012 16:42:13 +0100 Subject: [PATCH 006/691] [FIX] spelling error bzr revid: tde@openerp.com-20120201154213-utvgy12zt49c7jcq --- addons/mail/mail_group_view.xml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/addons/mail/mail_group_view.xml b/addons/mail/mail_group_view.xml index d6b852a2cbe..ee92758d5f9 100644 --- a/addons/mail/mail_group_view.xml +++ b/addons/mail/mail_group_view.xml @@ -116,7 +116,7 @@ - + Groups mail.group form @@ -150,22 +150,24 @@ - + - + - + + + - - + - + + + - + - - - + - + + + + + \ No newline at end of file diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 23c131ec66b..c1e8f7aa098 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -82,7 +82,7 @@ class mail_thread(osv.osv): }) return super(mail_thread, self).copy(cr, uid, id, default, context=context) - def message_append(self, cr, uid, threads, subject, body_text=None, email_to=False, + def message_append(self, cr, uid, threads, subject, body_text=None, type='email', email_to=False, email_from=False, email_cc=None, email_bcc=None, reply_to=None, email_date=None, message_id=False, references=None, attachments=None, body_html=None, subtype=None, headers=None, @@ -166,7 +166,8 @@ class mail_thread(osv.osv): 'message_id': message_id, 'body_text': body_text or (hasattr(thread, 'description') and thread.description or False), 'attachment_ids': [(6, 0, to_attach)], - 'state' : 'received', + 'state': 'received', + 'type': type, } if email_from: @@ -215,9 +216,12 @@ class mail_thread(osv.osv): to determine the model of the thread to update (instead of the current model). """ + # 6.2 Social feature: add default email type for old API + if not 'type' in msg_dict: msg_dict['type'] = 'email' return self.message_append(cr, uid, ids, subject = msg_dict.get('subject'), body_text = msg_dict.get('body_text'), + type = msg_dict.get('type'), email_to = msg_dict.get('to'), email_from = msg_dict.get('from'), email_cc = msg_dict.get('cc'), @@ -235,8 +239,15 @@ class mail_thread(osv.osv): context = context) # Message loading - def message_load(self): - pass + def message_load(self, cr, uid, ids, context=None): + """ Social feature added this method + loading message: search in mail.messages where res_id = ids, (res_)model = current model """ + msg_obj = self.pool.get('mail.message') + msg_ids = [] + for id in ids: + msg_ids += msg_obj.search(cr, uid, ['&', ('res_id', '=', id), ('model', '=', self._name)], context=context) + msgs = msg_obj.browse(cr, uid, ids) + return msgs #------------------------------------------------------ # Email specific @@ -484,8 +495,8 @@ class mail_thread(osv.osv): #------------------------------------------------------ # Note specific #------------------------------------------------------ - def message_append_note(self, context, type='notification'): - pass + def message_append_note(self, cr, uid, ids, subject, body, type='notification', context=None): + return self.message_append(cr, uid, ids, subject, body_text=body, type=type, context=context) #------------------------------------------------------ # Subscription mechanism From a83847d6f74f832fa9c49a70cf9560f51c281007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 2 Feb 2012 11:35:01 +0100 Subject: [PATCH 012/691] [ADD] Implementation of subscription mechanism methods bzr revid: tde@openerp.com-20120202103501-0tt9epmzkfcuf8xz --- addons/mail/mail_thread.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index c1e8f7aa098..8d5a05fb2bb 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -501,16 +501,27 @@ class mail_thread(osv.osv): #------------------------------------------------------ # Subscription mechanism #------------------------------------------------------ - def message_get_subscribers(self): - pass - - def message_subscribe(self): - pass - - def message_unsubscribe(self): - pass - + def message_get_subscribers(self, cr, uid, ids, context=None): + subscription_obj = self.pool.get('mail.subscription') + for id in ids: + sub_ids = subscription_obj.search(cr, uid, ['res_model': self._name, 'res_id': id], context=context) + subs = subscription_obj.browse(cr, uid, sub_ids, context=context) + return subs + def message_subscribe(self, cr, uid, ids, context=None): + subscription_obj = self.pool.get('mail.subscription') + subscriber_id = uid # TODO + for id in ids: + subscription_obj.create(cr, uid, {'res_model': self._name, 'res_id': id, 'user_id': subscriber_id}, context=context) + return True + def message_unsubscribe(self, cr, uid, ids, context=None): + subscription_obj = self.pool.get('mail.subscription') + subscriber_id = uid # TODO + sub_ids = [] + for id in ids: + sub_ids += subscription_obj.search(cr, uid, ['res_model': self._name, 'res_id': id, 'user_id': subscriber_id], context=context) + subscription_obj.unlink(cr, uid, ids, context=context) + return True # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 109647a109de0f0c45329570ff1b5e863359717e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 2 Feb 2012 12:26:57 +0100 Subject: [PATCH 013/691] [IMP] Added push of messages when creating one. Fixed bugs in mail_thread subscription mechanism. Added list views for subscriptions and notifications. Subscription is now unread by default. bzr revid: tde@openerp.com-20120202112657-zj406ck98n06imo9 --- addons/mail/mail_message.py | 20 +++++++++++--- addons/mail/mail_subscription.py | 5 ++-- addons/mail/mail_subscription_view.xml | 36 ++++++++++++++++++++++++++ addons/mail/mail_thread.py | 4 +-- 4 files changed, 57 insertions(+), 8 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 877ffd972b6..dfd2fe00b92 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -71,8 +71,8 @@ class mail_message_common(osv.osv_memory): _rec_name = 'subject' _columns = { 'subject': fields.char('Subject', size=512, required=True), - 'model': fields.char('Related Document model', size=128, select=1), # was rfeadonly - 'res_id': fields.integer('Related Document ID', select=1), # was rfeadonly + 'model': fields.char('Related Document model', size=128, select=1), # was readonly + 'res_id': fields.integer('Related Document ID', select=1), # was readonly 'date': fields.datetime('Date'), 'email_from': fields.char('From', size=128, help='Message sender, taken from user preferences. If empty, this is not a mail but a message.'), 'email_to': fields.char('To', size=256, help='Message recipients'), @@ -191,11 +191,23 @@ class mail_message(osv.osv): } #------------------------------------------------------ - # Note specific api + # Generic api #------------------------------------------------------ def create(self, cr, uid, vals, context=None): - return super(mail_message, self).create(cr, uid, vals, context) + msg_id = super(mail_message, self).create(cr, uid, vals, context) + # push the message to suscribed users + subscription_obj = self.pool.get('mail.subscription') + notification_obj = self.pool.get('mail.notification') + sub_ids = subscription_obj.search(cr, uid, ['&', ('res_model', '=', vals['model']), ('user_id', '=', uid)], context=context) + subs = subscription_obj.browse(cr, uid, sub_ids, context=context) + for sub in subs: + notification_obj.create(cr, uid, {'user_id': sub.user_id, 'message_id': msg_id}, context=context) + return msg_id + + #------------------------------------------------------ + # Note specific api + #------------------------------------------------------ def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False): if not context or not context.has_key('filter_search'): diff --git a/addons/mail/mail_subscription.py b/addons/mail/mail_subscription.py index f250ddc42e6..89750c47f5f 100644 --- a/addons/mail/mail_subscription.py +++ b/addons/mail/mail_subscription.py @@ -30,7 +30,7 @@ class mail_subscription(osv.osv): A subscription can be of following: - res_model: model of the followed objects - res_id: ID of resource OR - - res_domain: a domain filtering followed objects + - res_domain: a domain filtering followed objects - currently removed """ _name = 'mail.subscription' @@ -38,7 +38,7 @@ class mail_subscription(osv.osv): _columns = { 'res_model': fields.char('Related Document model', size=128, select=1), 'res_id': fields.integer('Related Document ID', select=1), - 'res_domain': fields.char('res_domain', size=256), + #'res_domain': fields.char('res_domain', size=256), 'user_id': fields.integer('Related User ID', select=1), } @@ -63,6 +63,7 @@ class mail_notification(osv.osv): } _defaults = { + 'read': False, } mail_notification() diff --git a/addons/mail/mail_subscription_view.xml b/addons/mail/mail_subscription_view.xml index 75f0408f341..2850cd206a1 100644 --- a/addons/mail/mail_subscription_view.xml +++ b/addons/mail/mail_subscription_view.xml @@ -2,6 +2,42 @@ + + + + mail.subscription.tree + mail.subscription + tree + 10 + + + + + + + + + + + + + mail.notification.tree + mail.notification + tree + 10 + + + + + + + + + Subscriptions mail.subscription diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 8d5a05fb2bb..e9df98ee955 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -504,7 +504,7 @@ class mail_thread(osv.osv): def message_get_subscribers(self, cr, uid, ids, context=None): subscription_obj = self.pool.get('mail.subscription') for id in ids: - sub_ids = subscription_obj.search(cr, uid, ['res_model': self._name, 'res_id': id], context=context) + sub_ids = subscription_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', '=', id)], context=context) subs = subscription_obj.browse(cr, uid, sub_ids, context=context) return subs @@ -520,7 +520,7 @@ class mail_thread(osv.osv): subscriber_id = uid # TODO sub_ids = [] for id in ids: - sub_ids += subscription_obj.search(cr, uid, ['res_model': self._name, 'res_id': id, 'user_id': subscriber_id], context=context) + sub_ids += subscription_obj.search(cr, uid, ['&', '&', ('res_model', '=', self._name), ('res_id', '=', id), ('user_id', '=', subscriber_id)], context=context) subscription_obj.unlink(cr, uid, ids, context=context) return True From 1b9b26693ccc932c820df7cc1ccbe56dfc490fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 2 Feb 2012 15:18:43 +0100 Subject: [PATCH 014/691] [ADD] Added first not-working draft for widget. Cleaned message search function. bzr revid: tde@openerp.com-20120202141843-4jq49mbd7a6ecq4b --- addons/mail/__openerp__.py | 16 +++- addons/mail/mail_message.py | 117 +++++++++++++++------------- addons/mail/static/src/js/mail.js | 53 +++++++------ addons/mail/static/src/xml/mail.xml | 17 ++++ 4 files changed, 126 insertions(+), 77 deletions(-) create mode 100644 addons/mail/static/src/xml/mail.xml diff --git a/addons/mail/__openerp__.py b/addons/mail/__openerp__.py index ed28c5be365..ec079463230 100644 --- a/addons/mail/__openerp__.py +++ b/addons/mail/__openerp__.py @@ -68,7 +68,19 @@ The main features are: 'installable': True, 'auto_install': False, 'certificate': '001056784984222247309', - 'images': ['images/customer_history.jpeg','images/messages_form.jpeg','images/messages_list.jpeg'], - 'css': ['static/src/css/mail_group.css'], + 'images': [ + 'images/customer_history.jpeg', + 'images/messages_form.jpeg', + 'images/messages_list.jpeg', + ], + 'css': [ + 'static/src/css/mail_group.css', + ], + 'js': [ + 'static/src/js/mail.js', + ], + 'qweb': [ + 'static/src/xml/mail.xml', + ], } # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index dfd2fe00b92..b13d9a3d389 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -205,70 +205,81 @@ class mail_message(osv.osv): notification_obj.create(cr, uid, {'user_id': sub.user_id, 'message_id': msg_id}, context=context) return msg_id + def get_pushed_messages(self, cr, uid, context=None): + """Wall: get messages to display""" + notification_obj = self.pool.get('mail.notification') + notification_ids = notification_obj.search(cr, uid, [('user_id', '=', uid)], context=context) + notifications = notification_obj.browse(cr, uid, notification_ids, context=context) + + # TODO / REMARK: classify based on res_model / res_id to have a 1_level hierarchy ? + + return notifications + + #------------------------------------------------------ # Note specific api #------------------------------------------------------ - def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False): - if not context or not context.has_key('filter_search'): - return super(mail_message, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count) + #def tmp_backup(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False): + #if not context or not context.has_key('filter_search'): + #return super(mail_message, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count) - # get subscriptions - sub_obj = self.pool.get('mail.subscription') - sub_ids = sub_obj.search(cr, uid, [('user_id', '=', uid)]) - subs = sub_obj.browse(cr, uid, sub_ids) + ## get subscriptions + #sub_obj = self.pool.get('mail.subscription') + #sub_ids = sub_obj.search(cr, uid, [('user_id', '=', uid)]) + #subs = sub_obj.browse(cr, uid, sub_ids) - # stock tweets to find - res_model_ids_dict = {} - res_model_all_list = [] + ## stock tweets to find + #res_model_ids_dict = {} + #res_model_all_list = [] - # check all subscriptions - for sub in subs: - if sub.res_model and sub.res_id == 0 and sub.res_domain == False: - print "s-1" - if sub.res_model not in res_model_all_list: - res_model_all_list.append(sub.res_model) - elif sub.res_model and sub.res_id: - print "s-2" - if res_model_ids_dict.has_key(sub.res_model): - res_model_ids_dict[sub.res_model].append(sub.res_id) - else: - res_model_ids_dict[sub.res_model] = [sub.res_id] - elif sub.res_model and sub.res_domain: - print "s-3" - res_obj = self.pool.get(sub.res_model) - print sub.res_domain - #res_ids = res_obj.search(cr, uid, [('id', 'in', [1,2])]) - res_ids = res_obj.search(cr, uid, eval(sub.res_domain)) - if res_model_ids_dict.has_key(sub.res_model): - res_model_ids_dict[sub.res_model] += res_ids - else: - res_model_ids_dict[sub.res_model] = res_ids - print 'cacaprout' - else: - print 'erreur !!!' - print sub + ## check all subscriptions + #for sub in subs: + #if sub.res_model and sub.res_id == 0 and sub.res_domain == False: + #print "s-1" + #if sub.res_model not in res_model_all_list: + #res_model_all_list.append(sub.res_model) + #elif sub.res_model and sub.res_id: + #print "s-2" + #if res_model_ids_dict.has_key(sub.res_model): + #res_model_ids_dict[sub.res_model].append(sub.res_id) + #else: + #res_model_ids_dict[sub.res_model] = [sub.res_id] + #elif sub.res_model and sub.res_domain: + #print "s-3" + #res_obj = self.pool.get(sub.res_model) + #print sub.res_domain + ##res_ids = res_obj.search(cr, uid, [('id', 'in', [1,2])]) + #res_ids = res_obj.search(cr, uid, eval(sub.res_domain)) + #if res_model_ids_dict.has_key(sub.res_model): + #res_model_ids_dict[sub.res_model] += res_ids + #else: + #res_model_ids_dict[sub.res_model] = res_ids + #print 'cacaprout' + #else: + #print 'erreur !!!' + #print sub - # add fully-followed domains - args.append('|') - args.append(['model', 'in', res_model_all_list]) + ## add fully-followed domains + #args.append('|') + #args.append(['model', 'in', res_model_all_list]) - # add partially-followed domains - for x in range(0, len(res_model_ids_dict.keys())-1): - args.append('|') + ## add partially-followed domains + #for x in range(0, len(res_model_ids_dict.keys())-1): + #args.append('|') - for res_model in res_model_ids_dict.keys(): - if res_model not in res_model_all_list: - args.append('&') - args.append(['model', '=', res_model]) - args.append(['res_id', 'in', res_model_ids_dict[res_model]]) + #for res_model in res_model_ids_dict.keys(): + #if res_model not in res_model_all_list: + #args.append('&') + #args.append(['model', '=', res_model]) + #args.append(['res_id', 'in', res_model_ids_dict[res_model]]) - if context and context.has_key('filter_search'): - pass - else: - args = [] - print args - return super(mail_message, self).search(cr, uid, args, offset=offset, limit=limit,order=order, context=context, count=count) + #if context and context.has_key('filter_search'): + #pass + #else: + #args = [] + #print args + #return super(mail_message, self).search(cr, uid, args, offset=offset, limit=limit,order=order, context=context, count=count) #------------------------------------------------------ # E-Mail api diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 2e81741f62a..6e23d813702 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -1,25 +1,34 @@ openerp.mail = function(session) { - -var mail = session.mail = {}; - -mail.Wall = session.web.Widget.extend({ - init: function(parent) { - }, - start: function() { - this.$element - }, -}); - -session.ThreadView - -session.MessgageInput - - - -var w = new session.mail.ThreadView(this); - -w.appendTo($("div.wall")); - - + + var mail = session.mail = {}; + + mail.Wall = session.web.Widget.extend({ + init: function(parent) { + }, + start: function() { +// this.$element + }, + }); + + mail.ThreadView = session.web.Widget.extend({ + template: 'MailTest', + + init: function(parent) { + }, + + start: function() { +// this.$element + }, + }); + + mail.MessgageInput = session.web.Widget.extend({ + }); + + + var tv = new mail.ThreadView(this); +// tv.appendTo($("div.wall")); +// tv.appendTo($("body")); + }; + // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml new file mode 100644 index 00000000000..005b4b23a79 --- /dev/null +++ b/addons/mail/static/src/xml/mail.xml @@ -0,0 +1,17 @@ + + \ No newline at end of file From babb03a00fcf01534c3b8bde56710c3799c6af2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 3 Feb 2012 09:48:25 +0100 Subject: [PATCH 015/691] First draft of javascript work for threadview bzr revid: tde@openerp.com-20120203084825-nyskuc8kxlljox0z --- addons/crm/crm_lead_view.xml | 43 +++++++++++++++++-------------- addons/mail/mail_thread.py | 1 + addons/mail/mail_thread_view.xml | 1 + addons/mail/static/src/js/mail.js | 5 ++-- 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index 44d83f47634..6218d00f044 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -547,27 +547,30 @@ - + - - - - - -
- +
@@ -25,12 +25,14 @@
-
+
Image
-
-
-
- +
+

+
+
+ +

From b6739df2973dd7743a38165ce6e69c217b50d9ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 7 Feb 2012 11:16:57 +0100 Subject: [PATCH 025/691] Tmp action button add for res_log testing purpose bzr revid: tde@openerp.com-20120207101657-phoxiwpa5q4g35sk --- addons/mail/mail_group.py | 11 +++++++---- addons/mail/mail_group_view.xml | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py index ff634e58d70..50141bf27a0 100644 --- a/addons/mail/mail_group.py +++ b/addons/mail/mail_group.py @@ -49,11 +49,14 @@ class mail_group(osv.osv): return True - def action_follow(self, cr, uid, ids, context={}): - return self.message_subscribe(cr, uid, ids, context=context) + def action_test(self, cr, uid, ids, context={}): + for o in self.browse(cr, uid, ids): + message = _('You are doing things with the group %s, wooooh !') % (o.name,) + self.log(cr, uid, o.id, message) + return True - def action_unfollow(self, cr, uid, ids, context={}): - return self.message_unsubscribe(cr, uid, ids, context=context) + def action_null(self, cr, uid, ids, context={}): + return True _columns = { #'group_id': fields.many2one('res.groups', required=True, ondelete='cascade', diff --git a/addons/mail/mail_group_view.xml b/addons/mail/mail_group_view.xml index ff489b09734..7ec4e26b25b 100644 --- a/addons/mail/mail_group_view.xml +++ b/addons/mail/mail_group_view.xml @@ -103,6 +103,9 @@
-
-

- 00000000 - 11111111 - 00000000 - 11111111 - 00000000 - 11111111 - 00000000 - 11111111 -

-
+ + zmeofizepofinzepfoiznepfoizpfozeinfpzoeinfpoznf zfe zef zef ze fz efz efz ef zef ze fz efznf zfe zef zef ze fz efz efz ef zef ze fz efznf zfe zef zef ze fz efz efz ef zef ze fz ef +
Image

-
-
- + zmeofizepofinzepfoiznepfoizpfozeinfpzoeinfpoznf zfe zef zef ze fz efz efz ef zef ze fz efznf zfe zef zef ze fz efz efz ef zef ze fz efznf zfe zef zef ze fz efz efz ef zef ze fz ef + + + +

From cff98a3aeb4b2308d00dc4b91b283ab79e322c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 8 Feb 2012 16:25:21 +0100 Subject: [PATCH 027/691] [IMP] Improved ThreadView widget display; cleaned ThreadView widget js code; added basic access rules; added message_mark_done method to clean a mail.thread of its need_action_user_id; added auto-push of notifications if user requested to perform an action is not following the object; added first draft of messaging mechanism in hr_holidays bzr revid: tde@openerp.com-20120208152521-68i4nekjj8mnuyc8 --- addons/hr_holidays/hr_holidays.py | 21 ++++++++++- addons/hr_holidays/hr_holidays_view.xml | 1 + addons/mail/mail_group.py | 6 --- addons/mail/mail_group_view.xml | 12 ------ addons/mail/mail_message.py | 10 ++++- addons/mail/mail_thread.py | 17 ++++++--- addons/mail/mail_thread_view.xml | 10 +++++ addons/mail/security/ir.model.access.csv | 2 + addons/mail/static/src/css/mail.css | 47 ++++++++++++++++-------- addons/mail/static/src/js/mail.js | 38 +++++++------------ addons/mail/static/src/xml/mail.xml | 44 ++++++++++++---------- 11 files changed, 123 insertions(+), 85 deletions(-) diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index 3bb7a8e4982..2ddb6e87a3a 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -93,6 +93,7 @@ class hr_holidays(osv.osv): _name = "hr.holidays" _description = "Leave" _order = "type desc, date_from asc" + _inherit = ['mail.thread'] def _employee_get(self, cr, uid, context=None): ids = self.pool.get('hr.employee').search(cr, uid, [('user_id', '=', uid)], context=context) @@ -250,8 +251,16 @@ class hr_holidays(osv.osv): obj_emp = self.pool.get('hr.employee') ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)]) manager = ids2 and ids2[0] or False + self.holidays_validate_notificate(cr, uid, ids, context=context) return self.write(cr, uid, ids, {'state':'validate1', 'manager_id': manager}) + def holidays_validate_notificate(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids): + self.message_mark_done(cr, uid, [obj.id], context=context) + self.message_append_note(cr, uid, [obj.id], 'System notification', _("The %s request '%s' has been validated.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', context=context) + if obj.holiday_status_id.double_validation: + self.message_append_note(cr, uid, [obj.id], 'System notification', _("The %s request '%s' is waiting for second validation.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', context=context) + def holidays_validate2(self, cr, uid, ids, context=None): self.check_holidays(cr, uid, ids, context=context) obj_emp = self.pool.get('hr.employee') @@ -301,13 +310,23 @@ class hr_holidays(osv.osv): wf_service.trg_validate(uid, 'hr.holidays', leave_id, 'validate', cr) wf_service.trg_validate(uid, 'hr.holidays', leave_id, 'second_validate', cr) if holiday_ids: + self.holidays_valid2_notificate(self, cr, uid, [holiday_ids], context=context) self.write(cr, uid, holiday_ids, {'manager_id2': manager}) return True + + def holidays_valid2_notificate(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids): + self.message_append_note(cr, uid, [obj.id], 'System notification', _("The %s request '%s' has been double validated.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', context=context) def holidays_confirm(self, cr, uid, ids, context=None): self.check_holidays(cr, uid, ids, context=context) + self.holidays_confirm_notificate(cr, uid, ids, context=context) return self.write(cr, uid, ids, {'state':'confirm'}) - + + def holidays_confirm_notificate(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids): + self.message_append_note(cr, uid, [obj.id], 'System notification', _("The %s request '%s' has been confirmed and is waiting for validation.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', need_action_user_id=obj.employee_id.parent_id.user_id.id) + def holidays_refuse(self, cr, uid, ids, approval, context=None): obj_emp = self.pool.get('hr.employee') ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)]) diff --git a/addons/hr_holidays/hr_holidays_view.xml b/addons/hr_holidays/hr_holidays_view.xml index 22d4d6e567d..2096ae2bc61 100644 --- a/addons/hr_holidays/hr_holidays_view.xml +++ b/addons/hr_holidays/hr_holidays_view.xml @@ -95,6 +95,7 @@ +
+
+
\ No newline at end of file From 9efc4714f26757a127861119e549f7718af3e136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 9 Feb 2012 11:04:47 +0100 Subject: [PATCH 030/691] [IMP] Wall: added parameters passing (filtering, message number to display, ..). Added My Wall (all feeds versus my feeds). bzr revid: tde@openerp.com-20120209100447-p8csuqq85jsexrdn --- addons/hr_holidays/hr_holidays.py | 8 ++++---- addons/mail/mail_message.py | 2 +- addons/mail/mail_message_view.xml | 7 +++++++ addons/mail/mail_thread_view.xml | 19 ++++++++++++++----- addons/mail/static/src/js/mail.js | 9 ++++++--- 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index 2ddb6e87a3a..8fd91c30581 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -257,9 +257,9 @@ class hr_holidays(osv.osv): def holidays_validate_notificate(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids): self.message_mark_done(cr, uid, [obj.id], context=context) - self.message_append_note(cr, uid, [obj.id], 'System notification', _("The %s request '%s' has been validated.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', context=context) + self.message_append_note(cr, uid, [obj.id], _('System notification'), _("The %s request '%s' has been validated.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', context=context) if obj.holiday_status_id.double_validation: - self.message_append_note(cr, uid, [obj.id], 'System notification', _("The %s request '%s' is waiting for second validation.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', context=context) + self.message_append_note(cr, uid, [obj.id], _('System notification'), _("The %s request '%s' is waiting for second validation.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', context=context) def holidays_validate2(self, cr, uid, ids, context=None): self.check_holidays(cr, uid, ids, context=context) @@ -316,7 +316,7 @@ class hr_holidays(osv.osv): def holidays_valid2_notificate(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids): - self.message_append_note(cr, uid, [obj.id], 'System notification', _("The %s request '%s' has been double validated.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', context=context) + self.message_append_note(cr, uid, [obj.id], _('System notification'), _("The %s request '%s' has been double validated.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', context=context) def holidays_confirm(self, cr, uid, ids, context=None): self.check_holidays(cr, uid, ids, context=context) @@ -325,7 +325,7 @@ class hr_holidays(osv.osv): def holidays_confirm_notificate(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids): - self.message_append_note(cr, uid, [obj.id], 'System notification', _("The %s request '%s' has been confirmed and is waiting for validation.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', need_action_user_id=obj.employee_id.parent_id.user_id.id) + self.message_append_note(cr, uid, [obj.id], _('System notification'), _("The %s request '%s' has been confirmed and is waiting for validation.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', need_action_user_id=obj.employee_id.parent_id.user_id.id) def holidays_refuse(self, cr, uid, ids, approval, context=None): obj_emp = self.pool.get('hr.employee') diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 2ecdad5ceca..28e02401244 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -216,7 +216,7 @@ class mail_message(osv.osv): notification_obj.create(cr, uid, {'user_id': vals['need_action_user_id'], 'message_id': msg_id}, context=context) return msg_id - def get_pushed_messages(self, cr, uid, context=None): + def get_pushed_messages(self, cr, uid, ids, filter_search=False, context=None): """Wall: get messages to display""" notification_obj = self.pool.get('mail.notification') notification_ids = notification_obj.search(cr, uid, [('user_id', '=', uid)], context=context) diff --git a/addons/mail/mail_message_view.xml b/addons/mail/mail_message_view.xml index 4ccf7d44323..0036897d411 100644 --- a/addons/mail/mail_message_view.xml +++ b/addons/mail/mail_message_view.xml @@ -230,6 +230,13 @@ (w)All Feeds mail.all_feeds + + + + + My Feeds + mail.all_feeds +
diff --git a/addons/mail/mail_thread_view.xml b/addons/mail/mail_thread_view.xml index 7bd503b0546..d2e557d06d8 100644 --- a/addons/mail/mail_thread_view.xml +++ b/addons/mail/mail_thread_view.xml @@ -51,26 +51,35 @@
- + + Feeds + + + + - - - + + My Feeds + + + + (w)All Feeds - + + diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index bd82399b88e..747276121fa 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -95,8 +95,9 @@ openerp.mail = function(session) { // QWeb template to use when rendering the object template: 'WallView', - init: function() { - this._super.apply(this, arguments); + init: function (parent, params) { + this._super(parent); + this.filter_search = params['filter_search']; /* DataSets */ this.ds_msg = new session.web.DataSet(this, 'mail.message'); }, @@ -104,8 +105,9 @@ openerp.mail = function(session) { start: function() { var self = this; this._super.apply(this, arguments); + console.log(this); self.$element.find('button.oe_mail_action_comment').bind('click', function () { self.do_comment(); }); - this.ds_msg.call('get_pushed_messages', []).then( + this.ds_msg.call('get_pushed_messages', [[], self.filter_search]).then( this.proxy('display_records')); }, @@ -114,6 +116,7 @@ openerp.mail = function(session) { }, fetch_messages: function () { + console.log('debug--fetch_messages'); return this.ds_msg.call('get_pushed_messages', []).then( this.proxy('display_records')); }, From 1d09919c1810c575d3c2bd74ef76b54ceca44d8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 10 Feb 2012 10:53:48 +0100 Subject: [PATCH 031/691] [FIX] Fixed bug with message dict not necessarily containing a 'type' entry bzr revid: tde@openerp.com-20120210095348-z8m7gqpse6hw9byr --- 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 28e02401244..58e5833fa49 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -198,7 +198,7 @@ class mail_message(osv.osv): def create(self, cr, uid, vals, context=None): # OpenSocial: notifications do not come from any user but from system - if vals['type'] == 'notification': vals['user_id'] = False + if vals.get('type') == 'notification': vals['user_id'] = False need_action_pushed = False msg_id = super(mail_message, self).create(cr, uid, vals, context) # push the message to suscribed users From 62a33c175a16471db9e9b2ad5555beaca27ddd7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 10 Feb 2012 11:25:37 +0100 Subject: [PATCH 032/691] [FIX] Fixed crash when assigning need_action_user_id to unexistent manager_id for holidays validation bzr revid: tde@openerp.com-20120210102537-rrvk58ttasnfmoqq --- addons/hr_holidays/hr_holidays.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index 8fd91c30581..a2acea4792d 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -325,7 +325,7 @@ class hr_holidays(osv.osv): def holidays_confirm_notificate(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids): - self.message_append_note(cr, uid, [obj.id], _('System notification'), _("The %s request '%s' has been confirmed and is waiting for validation.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', need_action_user_id=obj.employee_id.parent_id.user_id.id) + self.message_append_note(cr, uid, [obj.id], _('System notification'), _("The %s request '%s' has been confirmed and is waiting for validation.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', need_action_user_id = obj.employee_id.parent_id.user_id.id if obj.employee_id.parent_id else False) def holidays_refuse(self, cr, uid, ids, approval, context=None): obj_emp = self.pool.get('hr.employee') From 5042ba24658d48ffbd500484b6e01c0712f0ada5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 10 Feb 2012 11:52:23 +0100 Subject: [PATCH 033/691] [IMP] Cleaned xml, css and js for ThreadView. bzr revid: tde@openerp.com-20120210105223-fv24nic79ycldc2i --- addons/mail/static/src/css/mail.css | 75 ++++++++++++++++++++++------- addons/mail/static/src/js/mail.js | 26 +++++----- addons/mail/static/src/xml/mail.xml | 33 ++++++++----- 3 files changed, 93 insertions(+), 41 deletions(-) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 906bdbff6cf..baf7a98d71f 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -1,43 +1,74 @@ /** ThreadView widget **/ .oe_mail_main { + overflow: auto; + padding: 5px 5px 5px 5px; } +/* 2 columns view */ +.oe_mail_main_left { + float: left; + width: 65%; +} + +.oe_mail_main_right { + float: right; + width: 34%; +} + +/* Left-side CSS */ .oe_mail_actions { - padding-bottom: 10px; + margin-bottom: 10px; } .oe_mail_post_comment { - width: 65%; - padding-bottom: 10px; + margin-bottom: 10px; } -.oe_mail_comments { - width: 65%; +.oe_mail_button_follow, .oe_mail_button_unfollow, .oe_mail_button_getfollowers, .oe_mail_button_hidefollowers { + width: 100px; +} + +.oe_mail_button_comment { + width: 150px; +} + +.oe_mail_action_textarea { + width: 60%; + height: 50px; + padding: 5px; +} + +.oe_mail_action_comment { } .oe_mail_msg { - width: 65%; -/* border: 1px solid #998877; */ - padding: 10px 0px 10px 0px; } -.oe_mail_msg:after { +/*.oe_mail_msg:after { content: ""; display: block; clear: both; +}*/ + +.oe_mail_comment { + white-space: normal; + margin-bottom: 5px; } .oe_mail_msg_image { float: left; - width: 9%; + width: 14%; +} + +.oe_mail_msg_image img { + width: 80%; + margin-left: 10%; } .oe_mail_msg_content { - width: 89%; - margin-left: 10%; -/* border: 1px solid #557722; */ - overflow: hidden; + width: 85%; + margin-left: 15%; } .oe_mail_msg_p { @@ -48,14 +79,24 @@ .oe_mail_msg_body { } -.oe_mail_msg_author { +.oe_mail_msg_author, .oe_mail_msg_author a { color: #4E43E7; } -.oe_mail_msg_need_action { +.oe_mail_msg_need_action, .oe_mail_msg_need_action a { color: #C03000; } -.oe_mail_msg_date { +.oe_mail_msg_date, .oe_mail_msg_date a { color: #4E43E7; } + +/* Right-side CSS */ +.oe_mail_followers_vignette { + float: left; + width: 20%%; +} + +.oe_mail_followers_vignette img { + width: 80%; +} diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 747276121fa..93a333335a8 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -27,15 +27,15 @@ openerp.mail = function(session) { var self = this; this._super.apply(this, arguments); /* bind follow and unfollow buttons */ - self.$element.find('button.oe_mail_action_follow').bind('click', function () { self.do_follow(); }); - self.$element.find('button.oe_mail_action_follow').hide(); - self.$element.find('button.oe_mail_action_unfollow').bind('click', function () { self.do_unfollow(); }); - self.$element.find('button.oe_mail_action_unfollow').hide(); - self.$element.find('button.oe_mail_action_comment').bind('click', function () { self.do_comment(); }); + self.$element.find('button.oe_mail_button_follow').bind('click', function () { self.do_follow(); }); + self.$element.find('button.oe_mail_button_follow').hide(); + self.$element.find('button.oe_mail_button_unfollow').bind('click', function () { self.do_unfollow(); }); + self.$element.find('button.oe_mail_button_unfollow').hide(); + self.$element.find('button.oe_mail_button_comment').bind('click', function () { self.do_comment(); }); /* find wich (un)follow buttons to show */ var call_res = this.ds.call('message_is_subscriber', [[this.session.uid]]).then(function (records) { - if (records == true) { self.follow_state = 1; self.$element.find('button.oe_mail_action_unfollow').show(); } - else { self.follow_state = 0; self.$element.find('button.oe_mail_action_follow').show(); } + if (records == true) { self.follow_state = 1; self.$element.find('button.oe_mail_button_unfollow').show(); } + else { self.follow_state = 0; self.$element.find('button.oe_mail_button_follow').show(); } }); }, @@ -56,27 +56,27 @@ openerp.mail = function(session) { }, display_records: function (records) { - this.$element.find('div.oe_mail_comments').empty(); + this.$element.find('div.oe_mail_msg').empty(); var self = this; _(records).each(function (record) { var template = 'ThreadMsgView'; var render_res = session.web.qweb.render(template, { 'record': record, }); - $('
').html(render_res).appendTo(self.$element.find('div.oe_mail_comments')); + $('
').html(render_res).appendTo(self.$element.find('div.oe_mail_msg')); }); // this.timeout = setTimeout(this.proxy('fetch_messages'), 5000); }, do_follow: function () { - this.$element.find('button.oe_mail_action_unfollow').show(); - this.$element.find('button.oe_mail_action_follow').hide(); + this.$element.find('button.oe_mail_button_unfollow').show(); + this.$element.find('button.oe_mail_button_follow').hide(); return this.ds_sub.create({'res_model': this.view.model, 'user_id': this.session.uid, 'res_id': this.view.datarecord.id}).then(); }, do_unfollow: function () { - this.$element.find('button.oe_mail_action_follow').show(); - this.$element.find('button.oe_mail_action_unfollow').hide(); + this.$element.find('button.oe_mail_button_follow').show(); + this.$element.find('button.oe_mail_button_unfollow').hide(); return this.ds.call('message_unsubscribe', [[this.view.datarecord.id]]).then(); }, diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index 58e242829b6..72fbf8d0f88 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -3,17 +3,28 @@
OpenSocial
-
- - +
+
+ + +
+
+
+ +
+
+
+
+
-
-
- -
-
+
+ + +
+
+
Image
@@ -23,15 +34,15 @@ OpenERP System Notification
- + - - Need action + - Need action by

- +

From 628989451d3f4ceab62dfdfce110d126b8f0b96b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 10 Feb 2012 13:42:53 +0100 Subject: [PATCH 034/691] [IMP] Changed mail.subscription.user_id field from integer to many2one bzr revid: tde@openerp.com-20120210124253-mx7vgxhmzpfant62 --- addons/mail/mail_subscription.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/mail/mail_subscription.py b/addons/mail/mail_subscription.py index c5b5407190b..eaf53bc1c17 100644 --- a/addons/mail/mail_subscription.py +++ b/addons/mail/mail_subscription.py @@ -39,7 +39,8 @@ class mail_subscription(osv.osv): select=1, required=True), 'res_id': fields.integer('Related Document ID', select=1), #'res_domain': fields.char('res_domain', size=256), - 'user_id': fields.integer('Related User ID', select=1, required=True), + 'user_id': fields.many2one('res.users', string='Related User ID', + ondelete='cascade', required=True, select=1), } _defaults = { } From a123480d2c123f011265eff253d787cca27fb57f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 10 Feb 2012 13:43:48 +0100 Subject: [PATCH 035/691] [IMP] Added a 'get followers' button on ThreadWidget. Basic displaying of results added. bzr revid: tde@openerp.com-20120210124348-8s73xmswnfypqhx6 --- addons/mail/mail_thread.py | 7 +++++++ addons/mail/static/src/css/mail.css | 2 +- addons/mail/static/src/js/mail.js | 28 +++++++++++++++++++++++----- addons/mail/static/src/xml/mail.xml | 10 +++++----- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index f582bc50062..68bf4429d18 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -543,6 +543,13 @@ class mail_thread(osv.osv): subs = subscription_obj.browse(cr, uid, sub_ids, context=context) return subs + def message_get_subscribers_web(self, cr, uid, ids, context=None): + subscription_obj = self.pool.get('mail.subscription') + for id in ids: + sub_ids = subscription_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', '=', id)], context=context) + subs = subscription_obj.read(cr, uid, sub_ids, context=context) + return subs + def message_is_subscriber(self, cr, uid, ids, context=None): for subscription in self.message_get_subscribers(cr, uid, ids, context=context): if subscription.user_id == uid: return True diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index baf7a98d71f..0d153ce0c06 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -25,7 +25,7 @@ margin-bottom: 10px; } -.oe_mail_button_follow, .oe_mail_button_unfollow, .oe_mail_button_getfollowers, .oe_mail_button_hidefollowers { +.oe_mail_button_follow, .oe_mail_button_unfollow, .oe_mail_button_followers { width: 100px; } diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 93a333335a8..fa7037bcacb 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -32,6 +32,7 @@ openerp.mail = function(session) { self.$element.find('button.oe_mail_button_unfollow').bind('click', function () { self.do_unfollow(); }); self.$element.find('button.oe_mail_button_unfollow').hide(); self.$element.find('button.oe_mail_button_comment').bind('click', function () { self.do_comment(); }); + self.$element.find('button.oe_mail_button_followers').bind('click', function () { self.do_toggle_followers(); }); /* find wich (un)follow buttons to show */ var call_res = this.ds.call('message_is_subscriber', [[this.session.uid]]).then(function (records) { if (records == true) { self.follow_state = 1; self.$element.find('button.oe_mail_button_unfollow').show(); } @@ -47,15 +48,18 @@ openerp.mail = function(session) { set_value: function() { this._super.apply(this, arguments); if (! this.view.datarecord.id) { return; } - return this.fetch_messages(); + return this.fetch_data(); }, - fetch_messages: function () { - return this.ds.call('message_load', [[this.view.datarecord.id]]).then( - this.proxy('display_records')); + fetch_data: function () { + var load_res = this.ds.call('message_load', [[this.view.datarecord.id]]).then( + this.proxy('display_comments')); + var follow_res = this.ds.call('message_get_subscribers_web', [[this.view.datarecord.id]]).then( + this.proxy('display_followers')); + return follow_res; }, - display_records: function (records) { + display_comments: function (records) { this.$element.find('div.oe_mail_msg').empty(); var self = this; _(records).each(function (record) { @@ -68,6 +72,16 @@ openerp.mail = function(session) { // this.timeout = setTimeout(this.proxy('fetch_messages'), 5000); }, + display_followers: function (records) { + this.$element.find('div.oe_mail_followers').empty(); + var self = this; + _(records).each(function (record) { + console.log(record); +//
+ $('
').text(record.user_id[1]).appendTo(self.$element.find('div.oe_mail_followers')); + }); + }, + do_follow: function () { this.$element.find('button.oe_mail_button_unfollow').show(); this.$element.find('button.oe_mail_button_follow').hide(); @@ -85,6 +99,10 @@ openerp.mail = function(session) { return this.ds.call('message_append_note', [[this.view.datarecord.id], 'Reply comment', body_text, type='comment']).then( this.proxy('fetch_messages')); }, + + do_toggle_followers: function () { + this.$element.find('div.oe_mail_followers').toggle(); + }, }); /* Add WallView widget to registry */ diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index 72fbf8d0f88..ff8386f32b9 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -18,13 +18,13 @@
- - -
-
+
+ +
+
+
-
Image
From fcbd3d26dca82b0c265abd45504b083e54f9ad9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 Feb 2012 14:34:44 +0100 Subject: [PATCH 036/691] [IMP] hr: added parent_id in demo data for employees, allowing to test the need_action_user_id feature with hr.holidays with demo data bzr revid: tde@openerp.com-20120216133444-byv4m8vkh8g68uoe --- addons/hr/hr_demo.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/addons/hr/hr_demo.xml b/addons/hr/hr_demo.xml index b6a11f0b111..00b2ab325e4 100644 --- a/addons/hr/hr_demo.xml +++ b/addons/hr/hr_demo.xml @@ -165,6 +165,7 @@ Fabien Pinckaers + Grand-RosiÚre @@ -177,6 +178,7 @@ Antony Lesuisse + Grand-RosiÚre @@ -189,6 +191,7 @@ Minh Tran + Grand-RosiÚre @@ -202,6 +205,7 @@ Nicolas Vanhoren + Grand-RosiÚre @@ -214,6 +218,7 @@ Stéphane Wirtel + Grand-RosiÚre @@ -226,6 +231,7 @@ Christophe Simonis + Grand-RosiÚre @@ -238,6 +244,7 @@ Quentin De Paoli + Grand-RosiÚre @@ -249,6 +256,7 @@ Fabien Meghazi + Grand-RosiÚre @@ -260,6 +268,7 @@ Francois Pietquin + Grand-RosiÚre @@ -272,6 +281,7 @@ Julien Thewys + Grand-RosiÚre @@ -296,6 +306,7 @@ Valérie Descamps + Grand-RosiÚre From 8e14b6a70661dc367e20357afb3550bf12798465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 Feb 2012 14:43:19 +0100 Subject: [PATCH 037/691] [FIX] hr: updated demo data for employee_fp referencing itself as manager bzr revid: tde@openerp.com-20120216134319-8r8ty5h3wbnrkd35 --- addons/hr/hr_demo.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addons/hr/hr_demo.xml b/addons/hr/hr_demo.xml index 00b2ab325e4..f82e2dac39e 100644 --- a/addons/hr/hr_demo.xml +++ b/addons/hr/hr_demo.xml @@ -165,7 +165,6 @@ Fabien Pinckaers - Grand-RosiÚre @@ -174,6 +173,10 @@ /9j/4AAQSkZJRgABAQEAZABkAAD/4gv4SUNDX1BST0ZJTEUAAQEAAAvoAAAAAAIAAABtbnRyUkdCIFhZWiAH2QADABsAFQAkAB9hY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAA9tYAAQAAAADTLQAAAAAp+D3er/JVrnhC+uTKgzkNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBkZXNjAAABRAAAAHliWFlaAAABwAAAABRiVFJDAAAB1AAACAxkbWRkAAAJ4AAAAIhnWFlaAAAKaAAAABRnVFJDAAAB1AAACAxsdW1pAAAKfAAAABRtZWFzAAAKkAAAACRia3B0AAAKtAAAABRyWFlaAAAKyAAAABRyVFJDAAAB1AAACAx0ZWNoAAAK3AAAAAx2dWVkAAAK6AAAAId3dHB0AAALcAAAABRjcHJ0AAALhAAAADdjaGFkAAALvAAAACxkZXNjAAAAAAAAAB9zUkdCIElFQzYxOTY2LTItMSBibGFjayBzY2FsZWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWFlaIAAAAAAAACSgAAAPhAAAts9jdXJ2AAAAAAAABAAAAAAFAAoADwAUABkAHgAjACgALQAyADcAOwBAAEUASgBPAFQAWQBeAGMAaABtAHIAdwB8AIEAhgCLAJAAlQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0ADVANsA4ADlAOsA8AD2APsBAQEHAQ0BEwEZAR8BJQErATIBOAE+AUUBTAFSAVkBYAFnAW4BdQF8AYMBiwGSAZoBoQGpAbEBuQHBAckB0QHZAeEB6QHyAfoCAwIMAhQCHQImAi8COAJBAksCVAJdAmcCcQJ6AoQCjgKYAqICrAK2AsECywLVAuAC6wL1AwADCwMWAyEDLQM4A0MDTwNaA2YDcgN+A4oDlgOiA64DugPHA9MD4APsA/kEBgQTBCAELQQ7BEgEVQRjBHEEfgSMBJoEqAS2BMQE0wThBPAE/gUNBRwFKwU6BUkFWAVnBXcFhgWWBaYFtQXFBdUF5QX2BgYGFgYnBjcGSAZZBmoGewaMBp0GrwbABtEG4wb1BwcHGQcrBz0HTwdhB3QHhgeZB6wHvwfSB+UH+AgLCB8IMghGCFoIbgiCCJYIqgi+CNII5wj7CRAJJQk6CU8JZAl5CY8JpAm6Cc8J5Qn7ChEKJwo9ClQKagqBCpgKrgrFCtwK8wsLCyILOQtRC2kLgAuYC7ALyAvhC/kMEgwqDEMMXAx1DI4MpwzADNkM8w0NDSYNQA1aDXQNjg2pDcMN3g34DhMOLg5JDmQOfw6bDrYO0g7uDwkPJQ9BD14Peg+WD7MPzw/sEAkQJhBDEGEQfhCbELkQ1xD1ERMRMRFPEW0RjBGqEckR6BIHEiYSRRJkEoQSoxLDEuMTAxMjE0MTYxODE6QTxRPlFAYUJxRJFGoUixStFM4U8BUSFTQVVhV4FZsVvRXgFgMWJhZJFmwWjxayFtYW+hcdF0EXZReJF64X0hf3GBsYQBhlGIoYrxjVGPoZIBlFGWsZkRm3Gd0aBBoqGlEadxqeGsUa7BsUGzsbYxuKG7Ib2hwCHCocUhx7HKMczBz1HR4dRx1wHZkdwx3sHhYeQB5qHpQevh7pHxMfPh9pH5Qfvx/qIBUgQSBsIJggxCDwIRwhSCF1IaEhziH7IiciVSKCIq8i3SMKIzgjZiOUI8Ij8CQfJE0kfCSrJNolCSU4JWgllyXHJfcmJyZXJocmtyboJxgnSSd6J6sn3CgNKD8ocSiiKNQpBik4KWspnSnQKgIqNSpoKpsqzysCKzYraSudK9EsBSw5LG4soizXLQwtQS12Last4S4WLkwugi63Lu4vJC9aL5Evxy/+MDUwbDCkMNsxEjFKMYIxujHyMioyYzKbMtQzDTNGM38zuDPxNCs0ZTSeNNg1EzVNNYc1wjX9Njc2cjauNuk3JDdgN5w31zgUOFA4jDjIOQU5Qjl/Obw5+To2OnQ6sjrvOy07azuqO+g8JzxlPKQ84z0iPWE9oT3gPiA+YD6gPuA/IT9hP6I/4kAjQGRApkDnQSlBakGsQe5CMEJyQrVC90M6Q31DwEQDREdEikTORRJFVUWaRd5GIkZnRqtG8Ec1R3tHwEgFSEtIkUjXSR1JY0mpSfBKN0p9SsRLDEtTS5pL4kwqTHJMuk0CTUpNk03cTiVObk63TwBPSU+TT91QJ1BxULtRBlFQUZtR5lIxUnxSx1MTU19TqlP2VEJUj1TbVShVdVXCVg9WXFapVvdXRFeSV+BYL1h9WMtZGllpWbhaB1pWWqZa9VtFW5Vb5Vw1XIZc1l0nXXhdyV4aXmxevV8PX2Ffs2AFYFdgqmD8YU9homH1YklinGLwY0Njl2PrZEBklGTpZT1lkmXnZj1mkmboZz1nk2fpaD9olmjsaUNpmmnxakhqn2r3a09rp2v/bFdsr20IbWBtuW4SbmtuxG8eb3hv0XArcIZw4HE6cZVx8HJLcqZzAXNdc7h0FHRwdMx1KHWFdeF2Pnabdvh3VnezeBF4bnjMeSp5iXnnekZ6pXsEe2N7wnwhfIF84X1BfaF+AX5ifsJ/I3+Ef+WAR4CogQqBa4HNgjCCkoL0g1eDuoQdhICE44VHhauGDoZyhteHO4efiASIaYjOiTOJmYn+imSKyoswi5aL/IxjjMqNMY2Yjf+OZo7OjzaPnpAGkG6Q1pE/kaiSEZJ6kuOTTZO2lCCUipT0lV+VyZY0lp+XCpd1l+CYTJi4mSSZkJn8mmia1ZtCm6+cHJyJnPedZJ3SnkCerp8dn4uf+qBpoNihR6G2oiailqMGo3aj5qRWpMelOKWpphqmi6b9p26n4KhSqMSpN6mpqhyqj6sCq3Wr6axcrNCtRK24ri2uoa8Wr4uwALB1sOqxYLHWskuywrM4s660JbSctRO1irYBtnm28Ldot+C4WbjRuUq5wro7urW7LrunvCG8m70VvY++Cr6Evv+/er/1wHDA7MFnwePCX8Lbw1jD1MRRxM7FS8XIxkbGw8dBx7/IPci8yTrJuco4yrfLNsu2zDXMtc01zbXONs62zzfPuNA50LrRPNG+0j/SwdNE08bUSdTL1U7V0dZV1tjXXNfg2GTY6Nls2fHadtr724DcBdyK3RDdlt4c3qLfKd+v4DbgveFE4cziU+Lb42Pj6+Rz5PzlhOYN5pbnH+ep6DLovOlG6dDqW+rl63Dr++yG7RHtnO4o7rTvQO/M8Fjw5fFy8f/yjPMZ86f0NPTC9VD13vZt9vv3ivgZ+Kj5OPnH+lf65/t3/Af8mP0p/br+S/7c/23//2Rlc2MAAAAAAAAALklFQyA2MTk2Ni0yLTEgRGVmYXVsdCBSR0IgQ29sb3VyIFNwYWNlIC0gc1JHQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAAYpkAALeFAAAY2lhZWiAAAAAAAAAAAABQAAAAAAAAbWVhcwAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACWFlaIAAAAAAAAAMWAAADMwAAAqRYWVogAAAAAAAAb6IAADj1AAADkHNpZyAAAAAAQ1JUIGRlc2MAAAAAAAAALVJlZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbiBJRUMgNjE5NjYtMi0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAA9tYAAQAAAADTLXRleHQAAAAAQ29weXJpZ2h0IEludGVybmF0aW9uYWwgQ29sb3IgQ29uc29ydGl1bSwgMjAwOQAAc2YzMgAAAAAAAQxEAAAF3///8yYAAAeUAAD9j///+6H///2iAAAD2wAAwHX/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCABaAGQDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDvvH/wU1XVJpp9Fj0S+TflVedo2/8AQCP/AB6vI9Z+DfxD0vfcx+ALn5f47G4hmb8lk3/+O16p8WPh1Lqs76l4ekiS9/59ppPLV/8AclHzRt/47/u14lrfiD4meEJIUutf8ZaXE00kUG/U5pIXkjZkdUYuyNhl+7/wL7tevRnP7Ml8zyMTCHN70X8jG1nSfEOjx79Y0PxBpSf3riwuIf8Ax4ptra0LTk03SZtY1X/j4ZF8iCaRvkhf+OXP8R/hX/gVdP4P+L3xPuNN1K9vfFslxptvD9mT7RaQ+Y1xKrBNrxxqfk/1n/fNcdryPeabZaakcr3FxdM1zd3MnmM8j8szZ/5af3mb5q3p8/2zlfJ8UdfU43xb4p1Ce1dIpI0indt33tzrtx1rn5rvULsJaW8/+q+bb/y0dv72P4quy2TzSTTNH8zOzN+7+4vzf0qPWdMuIZIXf/Wr8jbPvfIzDt/u0TgTTqQLWhpKkHnX3yW8u5F/ebWZuobHB4rv/B+rXCWiWz+VePLu8+L5WXyz/eRj83zVwdrpkqWrvdxyzW6f88rjasufSptNvfsDpbpJvZk+6/zQsx/hGfSrE/5jvNa0yL7J/aWleakSor3NtNuVrf5sbkZvvR/+g1hyXD/I/wDf+9/vVa8L69cabrP2a8+S3uPk2vceZby54+Zj92k8X6S+iT+d9zTbj5YJHk/1TfxRO394fw/3l+b+9UC/vRKUlw/l76ktLvfB/uP/AD5rMRll+eKSOb/ck3fyqOOWGGT5/KT+9+FaGfObD3Cbv9Z/5EorL+3WX8dxbZ/66LRQaH3tAm+/tf8Aruv/AKFXmviHTrS8fUIbm3imt7idknV4/MWVQzffQ/K2P4f/AB3bXqFqn/Eytk/g85f/AEKvPNW/4+7r/rvLuX/gTV5UD25nivjpNB8MWumeG7PzIYIHkup1+aRlluGQ8fxbliWJV3fN/DurJ0K4TWIE022/0Z0ulbb5m5k/eZZtw+83zfM1YXxjlf8A4WhqyeZK6QTKu1P721Dt/BWr1r4DeHrG51pL+aOKbyoPlb+4x/8AHV+9Xd8EeY8uHv1eUJ/AGnaPpP8Ax7/PAm6Xf82/e2yX/wBkqlqXg23sNaheazi/dXXzf3XjPDN/8VXuereG/t6eTD8kTI0Uq/7JX+jVS8Q6Db38E9tcx/61P3v930+8Kw9sdv1Y821b4e2L6b9mSzimif5tqe/5f99V5TrvgCbRLt0tvtMNu33oH2yL+RBr6T0K0vv7Jhs7+T/SLVPK83/nrs4V2/2j/FVLUtG86TZN5T/7VEKxE8NGZ8v6Tol3NrX2Z7OKaJvlZX+WN13fxjkN/vLXuvwdE8XidNP0u8udKa4gaKCVI45Gl2Lv8p0bI+7W34p8F6cnhPUNVhs4/Ngh3XO/5flC/M+3+L+7/e2v/srXkvwwu/EMXxa0m2tJPtk76pG3lvJ+8dVZfNf8IpHZ/wDvpauc+eEjCEPYzj5n0lqfgTRtY/5C/gzwlqkz/enuNMjWRvxXmsx/hN4Og2fZvDFjpUq/9A6/Zd3/AABkZa9I2O8nyfJF/e/ip8cSJ9z7/wDerzuaR6nJE84uPAE3nsth4v8AHOlwrgfZLS6tJI4jgdDJAzHP3uWP3uMDABXfMn+k3H++P/QVop88h8sT468M/tWeKLRbdtf8KaTrUkIj33EU72k0jD+NvvJuP+ytW9G+LX277bNbap9tia9klXT9Ujb7RFDJIx2JKv8Ac3fe3Mv+z91a+aQf8/Wtvw1cJbatazSXEcMSzKszS7tqRvw7NtBbbht3yq1dkIRPPnOTO78fTf2r471O5SOWF72682KL/WbN6r8u6vqP4DeHn0HwJBc38fky3XzbX+9FGP8A2Y1534r8DW9nr3hPUbYf6VeOlrth+75cFigjfkBufLdv/Qq+gf7OR9FTTYZNiRIsSt9KdafuKJOGo+85SM/xD4y0zSrTe9vfOip/yxt9zf8AfNc3aeNNO1KTZbfbod//AD827R/1rjfih4JvhcfufG/je3lZ90s8V/tX/cWJdqxrVHw14ImudTe8sJNXhi/dbYprhpFT+9I0rEs2f7tRCEeU3nOXMeqR6jElZ/8AwkOjWd+iXOqWMMv8KzXCrv8Azp/izSbtPDU1npsn/EwitfN3eXu/u5214ZfeHvFf9pWzw+KNJmfzm+1rcWHnR+Xu4ZFZN27b95f++aIQjMJzlA+j/EVzYaj8NfEF1p1zFcSrplyyqnzb9sbMv/oNfL/gP4g2GhXqfES18OfbVsoPssVh9r8nZcS/KX8zY3SLfjj+OvoD4S2mv217DDq/9mXNhdfPFc28fkttO5TFLFltrf7rba+cPHegpo/g3UE02DyVg1qy06WC3j3fvEhumdu//PJGqqPJ70SK05e7L+tD09P2rbl/+aaRf+FF/wDc9WR+1DeNvz8Pbddvrrcjf+0K+ZIILz+C01H5flbZaSf/ABFa1pb6ikbv/Z+pfc/js5F/pW/1Wkcv1zEf0j9APBtw3iDw1Ya3MI4JL+1humjhBKp5kSOFyRk4DAZ4zjOBnAKj+DZJ+GHhtmO0tpFkcf8AbrFRXkyep7kFeKZ+XoTdDN/31Uke1k2t91vl3LU09u9o+yX+L5aZLaXFtJCk0exZUWWNv70b9Gr1DyPjPuH4TunxC+GHh3X57yVr6yjRZ2MnmTLd26pFNv8A99Y0k/7bvur06C4/d7/ub6+Kf2btQ1628WT2FneXv9jJayX+oWqSN5bbNio5X+9uZPmr7G83946VySgdlKfP7walcWn33+fZ/f8AmqPw9qKald3SQx/JaorN+LMF/wDQaxtWR3k2fvXrJu9PtJrTzv7YlsH+ZPPhvPs+/wDvIvPzU+QXOegfZ/tOtTf63elr8q/98iuLv7fSb+ebztPtklt52iZvL/iDYb5f96uTjh8aXN28MN5KkqOv2a5SSFvNUfxKvP8A6DW5YQypG/nSedL9+WR/vPIeWZqvk5PtBz8/Q7fwn5Vs9t5PleVvX7n3du6vHvFOl3Fh8LYNWmcfaNW8VPdfJJ/D5N0q5avTvD3mzSJCnzu+77lY/wAfdOt7DwNpFhZx7LeDV49qvIzN/qbr5iTWcfi9Rz+H0PF7R38t/wDW/fb/AJaUX7/uH/d0+C3f5/8Af/8AiaL+L9xXccJ9XfCuRG+G/ht1dFDaTZnDdf8Aj3joqn8Kd/8AwrXw0q/w6PZA/X7NHRXjT+Jnqw+FHw1b+BtW1qO9mubP7Bv8v7M95+73sG+ZmUfP93/Zrf0T4TeHbFHudWurnV2RGdlU/Z4f/HSXb/vuu0gu3ufntpIn2/eien/aIXtLpPL+fyG3RfxV7Mzy4R5DzlLWyur/APsHRbCPTbCVGlu1i3bmhjVnbexyzZ27Vr6l0TUWvdI0nUBH811plpc7f+ulujV87fD3ZZ6l/pP753tZfPlf/lq3nKjf+O7K9d+G189z8PrPTXk/4mXhr/iUz/w7o4/+Pd/+BwbP++HrOtuXhjrb93vJ/syeaiP95krjNa+F/h6wvn1vRJPsdw3zyweW0lvK3+3Fkdf7ysrV1vh7VrSaTybn9y/8Na1/b6ZNH88kSP8A3ax55QOnkjM8ck8C32q7LZNc+wf7VpHJu+9/fZ2213Ph7Sf7BsEsH1S+v3VN8s99J50zsfvfPxWvHplokn+s+9Rqb2KSIn2iOH5Gllkm+VbeMLl3f/ZC/NROfORCHIcr408f33gzVtMh0e3sbnULpJZZFu42aNLUNs+XaQdzv/6B/tVn+M/iEnjDw9DbXOjyaVdWt6rM32jzoXxHKPvYDL/rK8n8Vay3iPxJpPiXy5Vt9Ukvfs0L/eSyXyvIXv8ANhPMP+0710W/ZpKb/v3G52raEIe7IxnWlzOJp2iff/ub/vU+dP3FYUd28MCTQyeTuT/vhhxWhpt99vg2XPlQ3H/jvP8AFxWhmfTvwgTzvhvoTf3dPtl/KCMUVD8E5kb4c6XGJYmaGJIXCSg7GRFUqfcYoryanxM9Wn8KPlK0l+x3c0M3mw733r/eRv8A4mtrzfOkSF4/9IV/mZPuuv8AeX/Zrn7lme0O9i22fjJzj7/+A/IVZ8OfNdw7ufk7/wC61eseVApSIln4s2fcSXzV/wC+1U/+hLXW6Lqc2lalDrdt9908i+i+6sqiuW8S/L4hh28fOvT/AHWrc0n/AFzr/Dvbjt92iYQOw1byr+B7/SpPv/eV/l6f3v8AaFY0fiHWbb5PM37P7/zf+PVn6MzKyKrEL5B4B44mdR+SgL9ABWncf8fb1A5zZNH4n1m5kRP3Sf7X+z+NcH8TPFV94jP/AAhXh64+XUX8rUr7/nuo5KJ/0zG3c3977v3auePpJE06ZUdlBTkA4BrnPBKquqaoyqAyae20gcr9PSnyomrVnDYfqX2e58QpbWf/AB5aXBFawf7vzb62p5dkaQ/wI7J/uLWFpKr/AGtN8o+bzc8df9KatOf/AFn/AANq1IgEc0Pl7/4Ef90tSWEv+nvN/AibV/H722qsf+r/AOB0R/8As8n/ALJQM6mzxPAssWzB/v8AX2/TFFY9uS0QLHJ96Kgs/9k= + + + + Antony Lesuisse From 67bb1396605c4e145cfd8b0c397a4232e5626de4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 Feb 2012 17:03:02 +0100 Subject: [PATCH 038/691] [REF] mail.thread: fixed an error in is_subscriber, cleaned code; mail.js: threadview widget: cleaned code bzr revid: tde@openerp.com-20120216160302-g5knaca3vie1ekot --- addons/mail/mail_thread.py | 53 ++++++++++-------------- addons/mail/static/src/js/mail.js | 62 +++++++++++++++++------------ addons/mail/static/src/xml/mail.xml | 2 +- 3 files changed, 59 insertions(+), 58 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 68bf4429d18..f63ebde836c 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -241,23 +241,19 @@ class mail_thread(osv.osv): # Message loading def message_load_ids(self, cr, uid, ids, context=None): - """ OpenSocial feature added this method - get ids of thread messages + """ OpenSocial feature: return thread messages ids (for web compatibility) + loading messages: search in mail.messages where res_id = ids, (res_)model = current model """ msg_obj = self.pool.get('mail.message') - msg_ids = [msg_obj.search(cr, uid, ['&', ('res_id', '=', id), ('model', '=', self._name)], context=context) for id in ids] - return msg_ids[0] + msg_ids = msg_obj.search(cr, uid, ['&', ('res_id', 'in', ids), ('model', '=', self._name)], context=context) + return msg_ids def message_load(self, cr, uid, ids, context=None): - """ OpenSocial feature added this method - loading message: search in mail.messages where res_id = ids, (res_)model = current model + """ OpenSocial feature: return thread messages + loading messages: search in mail.messages where res_id = ids, (res_)model = current model """ - msg_ids = [] - msg_obj = self.pool.get('mail.message') - for id in ids: - msg_ids += msg_obj.search(cr, uid, ['&', ('res_id', '=', id), ('model', '=', self._name)], context=context) - msgs = msg_obj.read(cr, uid, msg_ids, context=context) - return msgs + msg_ids = self.message_load_ids(cr, uid, ids, context=context) + return self.pool.get('mail.message').read(cr, uid, msg_ids, context=context) #------------------------------------------------------ # Email specific @@ -528,9 +524,10 @@ class mail_thread(osv.osv): Find by: res_id (thread id), model (self._name), need_action_user_id != false """ msg_obj = self.pool.get('mail.message') - for id in ids: - msg_ids = msg_obj.search(cr, uid, ['&', ('res_id', '=', id), ('model', '=', self._name)], context=context) - msg_obj.write(cr, uid, msg_ids, {'need_action_user_id': False}, context=context) + msg_ids = msg_obj.search(cr, uid, + ['&', '&', ('res_id', 'in', ids), ('model', '=', self._name), ('need_action_user_id', '!=', False)], context=context) + msg_obj.write(cr, uid, msg_ids, {'need_action_user_id': False}, context=context) + return True #------------------------------------------------------ # Subscription mechanism @@ -538,22 +535,17 @@ class mail_thread(osv.osv): def message_get_subscribers(self, cr, uid, ids, context=None): subscription_obj = self.pool.get('mail.subscription') - for id in ids: - sub_ids = subscription_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', '=', id)], context=context) - subs = subscription_obj.browse(cr, uid, sub_ids, context=context) - return subs - - def message_get_subscribers_web(self, cr, uid, ids, context=None): - subscription_obj = self.pool.get('mail.subscription') - for id in ids: - sub_ids = subscription_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', '=', id)], context=context) - subs = subscription_obj.read(cr, uid, sub_ids, context=context) + sub_ids = subscription_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) + subs = subscription_obj.read(cr, uid, sub_ids, context=context) return subs def message_is_subscriber(self, cr, uid, ids, context=None): - for subscription in self.message_get_subscribers(cr, uid, ids, context=context): - if subscription.user_id == uid: return True - return False + subscription_obj = self.pool.get('mail.subscription') + sub_ids = subscription_obj.search(cr, uid, + ['&', '&', ('res_model', '=', self._name), ('res_id', 'in', ids), ('user_id', '=', uid)], context=context) + if len(sub_ids) > 1: + print 'cacaprout error !' + return True if sub_ids else False def message_subscribe(self, cr, uid, ids, context=None): subscription_obj = self.pool.get('mail.subscription') @@ -565,9 +557,8 @@ class mail_thread(osv.osv): def message_unsubscribe(self, cr, uid, ids, context=None): subscription_obj = self.pool.get('mail.subscription') subscriber_id = uid # TODO - sub_ids = [] - for id in ids: - sub_ids += subscription_obj.search(cr, uid, ['&', '&', ('res_model', '=', self._name), ('res_id', '=', id), ('user_id', '=', subscriber_id)], context=context) + sub_ids = subscription_obj.search(cr, uid, + ['&', '&', ('res_model', '=', self._name), ('res_id', 'in', ids), ('user_id', '=', subscriber_id)], context=context) subscription_obj.unlink(cr, uid, sub_ids, context=context) return True diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index fa7037bcacb..aa1ed33fb6d 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -14,47 +14,55 @@ openerp.mail = function(session) { template: 'ThreadView', init: function() { -// this.timeout; this.follow_state = 0; this._super.apply(this, arguments); /* DataSets */ this.ds = new session.web.DataSet(this, this.view.model); - this.ds_sub = new session.web.DataSet(this, 'mail.subscription'); -// this.ds_msg = new session.web.DataSet(this, 'mail.message'); }, start: function() { var self = this; this._super.apply(this, arguments); - /* bind follow and unfollow buttons */ - self.$element.find('button.oe_mail_button_follow').bind('click', function () { self.do_follow(); }); - self.$element.find('button.oe_mail_button_follow').hide(); - self.$element.find('button.oe_mail_button_unfollow').bind('click', function () { self.do_unfollow(); }); - self.$element.find('button.oe_mail_button_unfollow').hide(); + /* bind buttons */ self.$element.find('button.oe_mail_button_comment').bind('click', function () { self.do_comment(); }); self.$element.find('button.oe_mail_button_followers').bind('click', function () { self.do_toggle_followers(); }); - /* find wich (un)follow buttons to show */ - var call_res = this.ds.call('message_is_subscriber', [[this.session.uid]]).then(function (records) { - if (records == true) { self.follow_state = 1; self.$element.find('button.oe_mail_button_unfollow').show(); } - else { self.follow_state = 0; self.$element.find('button.oe_mail_button_follow').show(); } - }); + self.$element.find('button.oe_mail_button_follow').bind('click', function () { self.do_follow(); }); + self.$element.find('button.oe_mail_button_unfollow').bind('click', function () { self.do_unfollow(); }); + /* hide follow/unfollow buttons */ + self.$element.find('button.oe_mail_button_follow').hide(); + self.$element.find('button.oe_mail_button_unfollow').hide(); }, stop: function () { -// clearTimeout(this.timeout); - this._super(); + console.log('stop'); + this._super.apply(this, arguments); }, set_value: function() { + var self = this; this._super.apply(this, arguments); + /* hide follow/unfollow buttons */ + self.$element.find('button.oe_mail_button_follow').hide(); + self.$element.find('button.oe_mail_button_unfollow').hide(); if (! this.view.datarecord.id) { return; } - return this.fetch_data(); + /* find wich (un)follow buttons to show */ + var call_res = this.ds.call('message_is_subscriber', [[this.view.datarecord.id]]).then(function (records) { + if (records == true) { self.follow_state = 1; self.$element.find('button.oe_mail_button_unfollow').show(); } + else { self.follow_state = 0; self.$element.find('button.oe_mail_button_follow').show(); } + }); + /* fetch comments and subscribers */ + this.fetch_subscribers(); + return this.fetch_comments(); }, - fetch_data: function () { + fetch_comments: function () { var load_res = this.ds.call('message_load', [[this.view.datarecord.id]]).then( this.proxy('display_comments')); - var follow_res = this.ds.call('message_get_subscribers_web', [[this.view.datarecord.id]]).then( + return load_res; + }, + + fetch_subscribers: function () { + var follow_res = this.ds.call('message_get_subscribers', [[this.view.datarecord.id]]).then( this.proxy('display_followers')); return follow_res; }, @@ -69,35 +77,37 @@ openerp.mail = function(session) { }); $('
').html(render_res).appendTo(self.$element.find('div.oe_mail_msg')); }); -// this.timeout = setTimeout(this.proxy('fetch_messages'), 5000); }, display_followers: function (records) { this.$element.find('div.oe_mail_followers').empty(); var self = this; _(records).each(function (record) { - console.log(record); //
$('
').text(record.user_id[1]).appendTo(self.$element.find('div.oe_mail_followers')); }); }, do_follow: function () { - this.$element.find('button.oe_mail_button_unfollow').show(); - this.$element.find('button.oe_mail_button_follow').hide(); - return this.ds_sub.create({'res_model': this.view.model, 'user_id': this.session.uid, 'res_id': this.view.datarecord.id}).then(); + this.do_toggle_follow(); + return this.ds.call('message_subscribe', [[this.view.datarecord.id]]).then(); }, do_unfollow: function () { - this.$element.find('button.oe_mail_button_follow').show(); - this.$element.find('button.oe_mail_button_unfollow').hide(); + this.do_toggle_follow(); return this.ds.call('message_unsubscribe', [[this.view.datarecord.id]]).then(); }, do_comment: function () { var body_text = this.$element.find('textarea').val(); return this.ds.call('message_append_note', [[this.view.datarecord.id], 'Reply comment', body_text, type='comment']).then( - this.proxy('fetch_messages')); + this.proxy('fetch_comments')); + }, + + do_toggle_follow: function () { + this.follow_state = 1 - this.follow_state; + this.$element.find('button.oe_mail_button_unfollow').toggle(); + this.$element.find('button.oe_mail_button_follow').toggle(); }, do_toggle_followers: function () { diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index ff8386f32b9..50e73f10326 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -56,4 +56,4 @@
- \ No newline at end of file + From 64164155d23453a7087dd0740da1783e6332300b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 Feb 2012 17:48:37 +0100 Subject: [PATCH 039/691] [FIX] mail_message: fixed notification creation, propagating a subscription model modification (from int to many2one); fixed unprotected accesses to 'need_action_user_id' key in vals dictionnary bzr revid: tde@openerp.com-20120216164837-jscxxu52sybvy7db --- addons/mail/mail_message.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 58e5833fa49..9ada617a177 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -209,10 +209,10 @@ class mail_message(osv.osv): ('res_id', '=', vals['res_id'])], context=context) subs = subscription_obj.browse(cr, uid, sub_ids, context=context) for sub in subs: - notification_obj.create(cr, uid, {'user_id': sub.user_id, 'message_id': msg_id}, context=context) - if vals['need_action_user_id'] == sub.user_id: need_action_pushed = True + notification_obj.create(cr, uid, {'user_id': sub.user_id.id, 'message_id': msg_id}, context=context) + if vals.get('need_action_user_id', False) == sub.user_id: need_action_pushed = True # push to need_action_user_id if user does not follow the object - if vals['need_action_user_id'] != False and not need_action_pushed: + if vals.get('need_action_user_id', False) and not need_action_pushed: notification_obj.create(cr, uid, {'user_id': vals['need_action_user_id'], 'message_id': msg_id}, context=context) return msg_id From 12514823e69781fdf6509c7e07dda2f9d6d67311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 Feb 2012 18:04:46 +0100 Subject: [PATCH 040/691] [FIX] Cleaned create method for mail_message; added protection against unknown keys in vals parameter bzr revid: tde@openerp.com-20120216170446-h4u8t3znp7p4lerb --- addons/mail/mail_message.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 9ada617a177..03eb57bfd0f 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -204,15 +204,19 @@ class mail_message(osv.osv): # push the message to suscribed users subscription_obj = self.pool.get('mail.subscription') notification_obj = self.pool.get('mail.notification') + # not pure-email: check for subscriptions + if not 'need_action_user_id' in vals: vals['need_action_user_id'] = False + if not 'model' in vals: vals['model'] = False + if not 'res_id' in vals: vals['res_id'] = 0 sub_ids = subscription_obj.search(cr, uid, ['&', ('res_model', '=', vals['model']), ('res_id', '=', vals['res_id'])], context=context) subs = subscription_obj.browse(cr, uid, sub_ids, context=context) for sub in subs: notification_obj.create(cr, uid, {'user_id': sub.user_id.id, 'message_id': msg_id}, context=context) - if vals.get('need_action_user_id', False) == sub.user_id: need_action_pushed = True + if vals['need_action_user_id'] == sub.user_id: need_action_pushed = True # push to need_action_user_id if user does not follow the object - if vals.get('need_action_user_id', False) and not need_action_pushed: + if vals['need_action_user_id'] and not need_action_pushed: notification_obj.create(cr, uid, {'user_id': vals['need_action_user_id'], 'message_id': msg_id}, context=context) return msg_id From b23dd504c4d572fad8478f040a36b3571066f2e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 20 Feb 2012 10:22:39 +0100 Subject: [PATCH 041/691] [FIX] Fixed template var name to match rev 2225 of web client bzr revid: tde@openerp.com-20120220092239-l1e35sv2l7qfzegx --- addons/mail/static/src/js/mail.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index aa1ed33fb6d..ae98891eda9 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -11,7 +11,7 @@ openerp.mail = function(session) { /* ThreadView widget: thread of comments */ mail.ThreadView = session.web.form.Field.extend({ // QWeb template to use when rendering the object - template: 'ThreadView', + form_template: 'ThreadView', init: function() { this.follow_state = 0; From b8612374d7f4b202a1f5c092bc7bd695864848a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 20 Feb 2012 12:17:05 +0100 Subject: [PATCH 042/691] [IMP] crm_case: removed generic notification when changing state. Messages are now delegated to upper modules, that will have to write consistent and useful notifications. bzr revid: tde@openerp.com-20120220111705-4q7x3ukgvnz3vhe1 --- addons/crm/crm.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/addons/crm/crm.py b/addons/crm/crm.py index 4ebb0b4796d..7775e442df7 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -393,7 +393,6 @@ class crm_case(crm_base): def case_open(self, cr, uid, ids, *args): """Opens Case""" cases = self.browse(cr, uid, ids) - self.message_append(cr, uid, cases, _('Open')) for case in cases: data = {'state': 'open', 'active': True } if not case.user_id: @@ -406,7 +405,6 @@ class crm_case(crm_base): """Closes Case""" cases = self.browse(cr, uid, ids) cases[0].state # to fill the browse record cache - self.message_append(cr, uid, cases, _('Close')) self.write(cr, uid, ids, {'state': 'done', 'date_closed': time.strftime('%Y-%m-%d %H:%M:%S'), }) @@ -430,7 +428,6 @@ class crm_case(crm_base): raise osv.except_osv(_('Error !'), _('You can not escalate, you are already at the top level regarding your sales-team category.')) self.write(cr, uid, [case.id], data) cases = self.browse(cr, uid, ids) - self.message_append(cr, uid, cases, _('Escalate')) self._action(cr, uid, cases, 'escalate') return True @@ -438,7 +435,6 @@ class crm_case(crm_base): """Cancels Case""" cases = self.browse(cr, uid, ids) cases[0].state # to fill the browse record cache - self.message_append(cr, uid, cases, _('Cancel')) self.write(cr, uid, ids, {'state': 'cancel', 'active': True}) self._action(cr, uid, cases, 'cancel') @@ -451,7 +447,6 @@ class crm_case(crm_base): """Marks case as pending""" cases = self.browse(cr, uid, ids) cases[0].state # to fill the browse record cache - self.message_append(cr, uid, cases, _('Pending')) self.write(cr, uid, ids, {'state': 'pending', 'active': True}) self._action(cr, uid, cases, 'pending') return True @@ -463,7 +458,6 @@ class crm_case(crm_base): state = 'open' cases = self.browse(cr, uid, ids) cases[0].state # to fill the browse record cache - self.message_append(cr, uid, cases, _('Draft')) self.write(cr, uid, ids, {'state': state, 'active': True}) self._action(cr, uid, cases, state) return True From 674680484179c93d424461011ce4e1503747b369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 20 Feb 2012 17:11:57 +0100 Subject: [PATCH 043/691] [REF] mail_thread: deleted unused mail_thread views, now unecessary since content is not managed by a message_ids o2m field anymore bzr revid: tde@openerp.com-20120220161157-b9m23nq1czt4uoy3 --- addons/mail/mail_thread_view.xml | 60 -------------------------------- 1 file changed, 60 deletions(-) diff --git a/addons/mail/mail_thread_view.xml b/addons/mail/mail_thread_view.xml index d2e557d06d8..a71ae040328 100644 --- a/addons/mail/mail_thread_view.xml +++ b/addons/mail/mail_thread_view.xml @@ -1,62 +1,12 @@ - - mail.thread.form - mail.thread - form - -
- - - - - - - - - -
- - - mail.thread.tree - mail.thread - tree - - - - - - - - - - Email Threads - mail.thread - tree,form - form - - - - - tree - - - - - - form - - - Feeds - - @@ -83,16 +33,6 @@ - -
From 1469deff854c9bf0369ece9c7f639d2fe0257b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 20 Feb 2012 18:21:06 +0100 Subject: [PATCH 044/691] [IMP] mail_thread API: message_get_subscribers now returns res.users read results instead of mail.subscription results. message_subscribe has now an optional parameter user_ids to subscribe ids in user_ids instead of uid. bzr revid: tde@openerp.com-20120220172106-fpjafkkvea0m1k93 --- addons/mail/mail_thread.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index f63ebde836c..e0a42f3cfe7 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -533,11 +533,16 @@ class mail_thread(osv.osv): # Subscription mechanism #------------------------------------------------------ - def message_get_subscribers(self, cr, uid, ids, context=None): + def message_get_subscribers_ids(self, cr, uid, ids, context=None): subscription_obj = self.pool.get('mail.subscription') sub_ids = subscription_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) subs = subscription_obj.read(cr, uid, sub_ids, context=context) - return subs + return [sub['user_id'] for sub in subs] + + def message_get_subscribers(self, cr, uid, ids, context=None): + user_ids = self.message_get_subscribers_ids(cr, uid, ids, context=context) + users = self.pool.get('res.users').read(cr, uid, user_ids, context=context) + return users def message_is_subscriber(self, cr, uid, ids, context=None): subscription_obj = self.pool.get('mail.subscription') @@ -547,12 +552,13 @@ class mail_thread(osv.osv): print 'cacaprout error !' return True if sub_ids else False - def message_subscribe(self, cr, uid, ids, context=None): + def message_subscribe(self, cr, uid, ids, user_ids = None, context=None): subscription_obj = self.pool.get('mail.subscription') - subscriber_id = uid # TODO + sub_user_ids = [uid] if user_ids is None else user_ids for id in ids: - subscription_obj.create(cr, uid, {'res_model': self._name, 'res_id': id, 'user_id': subscriber_id}, context=context) - return True + create_ids = [subscription_obj.create(cr, uid, {'res_model': self._name, 'res_id': id, 'user_id': user_id}, context=context) + for user_id in sub_user_ids] + return create_ids def message_unsubscribe(self, cr, uid, ids, context=None): subscription_obj = self.pool.get('mail.subscription') From 3a53f777dfc5e3ce640f78d36acf94524e002d43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 20 Feb 2012 18:22:30 +0100 Subject: [PATCH 045/691] [FIX] Propagated API modification: message_get_subscribers result are now read records from res.users bzr revid: tde@openerp.com-20120220172230-mj7vx5akh0xrmzs6 --- addons/mail/static/src/js/mail.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index ae98891eda9..b9404885b6a 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -84,7 +84,8 @@ openerp.mail = function(session) { var self = this; _(records).each(function (record) { //
- $('
').text(record.user_id[1]).appendTo(self.$element.find('div.oe_mail_followers')); + //$('
').text(record.user_id[1]).appendTo(self.$element.find('div.oe_mail_followers')); + $('
').text(record.name).appendTo(self.$element.find('div.oe_mail_followers')); }); }, From a2ef45aaebe2d75a7fb00c23276170bffbac3d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 20 Feb 2012 18:23:23 +0100 Subject: [PATCH 046/691] [IMP] hr_holidays: improved notifications, added notifications when creating or refusing a leave requet/allocation. bzr revid: tde@openerp.com-20120220172323-4kqkhxntcgx6g178 --- addons/hr_holidays/hr_holidays.py | 80 ++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index a2acea4792d..a8573b9bf7c 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -151,7 +151,12 @@ class hr_holidays(osv.osv): ('date_check2', "CHECK ( (type='add') OR (date_from <= date_to))", "The start date must be before the end date !"), ('date_check', "CHECK ( number_of_days_temp >= 0 )", "The number of days must be greater than 0 !"), ] - + + def create(self, cr, uid, vals, context=None): + obj_id = super(hr_holidays, self).create(cr, uid, vals, context=context) + self.create_notificate(cr, uid, [obj_id], context=context) + return obj_id + def _create_resource_leave(self, cr, uid, leaves, context=None): '''This method will create entry in resource calendar leave object at the time of holidays validated ''' obj_res_leave = self.pool.get('resource.calendar.leaves') @@ -253,13 +258,6 @@ class hr_holidays(osv.osv): manager = ids2 and ids2[0] or False self.holidays_validate_notificate(cr, uid, ids, context=context) return self.write(cr, uid, ids, {'state':'validate1', 'manager_id': manager}) - - def holidays_validate_notificate(self, cr, uid, ids, context=None): - for obj in self.browse(cr, uid, ids): - self.message_mark_done(cr, uid, [obj.id], context=context) - self.message_append_note(cr, uid, [obj.id], _('System notification'), _("The %s request '%s' has been validated.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', context=context) - if obj.holiday_status_id.double_validation: - self.message_append_note(cr, uid, [obj.id], _('System notification'), _("The %s request '%s' is waiting for second validation.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', context=context) def holidays_validate2(self, cr, uid, ids, context=None): self.check_holidays(cr, uid, ids, context=context) @@ -313,20 +311,12 @@ class hr_holidays(osv.osv): self.holidays_valid2_notificate(self, cr, uid, [holiday_ids], context=context) self.write(cr, uid, holiday_ids, {'manager_id2': manager}) return True - - def holidays_valid2_notificate(self, cr, uid, ids, context=None): - for obj in self.browse(cr, uid, ids): - self.message_append_note(cr, uid, [obj.id], _('System notification'), _("The %s request '%s' has been double validated.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', context=context) def holidays_confirm(self, cr, uid, ids, context=None): self.check_holidays(cr, uid, ids, context=context) self.holidays_confirm_notificate(cr, uid, ids, context=context) return self.write(cr, uid, ids, {'state':'confirm'}) - def holidays_confirm_notificate(self, cr, uid, ids, context=None): - for obj in self.browse(cr, uid, ids): - self.message_append_note(cr, uid, [obj.id], _('System notification'), _("The %s request '%s' has been confirmed and is waiting for validation.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', need_action_user_id = obj.employee_id.parent_id.user_id.id if obj.employee_id.parent_id else False) - def holidays_refuse(self, cr, uid, ids, approval, context=None): obj_emp = self.pool.get('hr.employee') ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)]) @@ -335,6 +325,7 @@ class hr_holidays(osv.osv): self.write(cr, uid, ids, {'state': 'refuse', 'manager_id': manager}) else: self.write(cr, uid, ids, {'state': 'refuse', 'manager_id2': manager}) + self.holidays_refuse_notificate(cr, uid, ids, approval, context=context) self.holidays_cancel(cr, uid, ids, context=context) return True @@ -362,6 +353,63 @@ class hr_holidays(osv.osv): if leaves_rest < record.number_of_days_temp: raise osv.except_osv(_('Warning!'),_('You cannot validate leaves for employee %s: too few remaining days (%s).') % (record.employee_id.name, leaves_rest)) return True + + # ----------------------------- + # OpenChatter and notifications + # ----------------------------- + + def create_notificate(self, cr, uid, ids, context=None): + obj = self.browse(cr, uid, ids, context=context)[0] + self.message_append_note(cr, uid, ids, _('System notification'), + _("""The %s request '%s' has been created and is in draft mode. In this mode, it can be modified freely. + Click on Confirm to confirm your request and ask for its validation by the managers.""") + % ('leave' if obj.type == 'remove' else 'allocation', obj.name), type='notification', context=context) + return True + + def message_get_subscribers(self, cr, uid, ids, context=None): + """OpenChatter: override message_get_subscribers to add : + - employee related user + - employee manager user, if it exists""" + users = super(hr_holidays, self).message_get_subscribers(cr, uid, ids, context=context) + user_ids = [] + for holidays in self.browse(cr, uid, ids, context=context): + user_ids.append(holidays.user_id.id) + if holidays.employee_id.parent_id: + user_ids.append(holidays.employee_id.parent_id.user_id.id) + users += self.pool.get('res.users').read(cr, uid, user_ids, context=context) + return users + + def holidays_confirm_notificate(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids): + self.message_append_note(cr, uid, [obj.id], _('System notification'), + _("The %s request '%s' has been confirmed. It is now waiting for validation by the manager.") + % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', + need_action_user_id = obj.employee_id.parent_id.user_id.id if obj.employee_id.parent_id else False) + + def holidays_validate_notificate(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids): + self.message_mark_done(cr, uid, [obj.id], context=context) + if obj.holiday_status_id.double_validation: + self.message_append_note(cr, uid, [obj.id], _('System notification'), + _("The %s request '%s' has been validated. A second validation of your request is necessary and is now pending.") + % ('leave' if obj.type == 'remove' else 'allocation', obj.name), type='notification', context=context) + else: + self.message_append_note(cr, uid, [obj.id], _('System notification'), + _("The %s request '%s' has been validated. The validation process is now over.") + % ('leave' if obj.type == 'remove' else 'allocation', obj.name), type='notification', context=context) + + def holidays_valid2_notificate(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids): + self.message_append_note(cr, uid, [obj.id], _('System notification'), + _("The %s request '%s' has been double validated. The validation process is now over.") + % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', context=context) + + def holidays_refuse_notificate(self, cr, uid, ids, approval, context=None): + for obj in self.browse(cr, uid, ids): + self.message_append_note(cr, uid, [obj.id], _('System notification'), + _("The %s request '%s' has been refused. The validation process is now over.") + % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', context=context) + hr_holidays() class resource_calendar_leaves(osv.osv): From 592a41fa3e493ca6de87f91201b574063a3ab43b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 21 Feb 2012 15:21:26 +0100 Subject: [PATCH 047/691] [FIX] mail.thread: fixed message_get_subscribers returning a tuple list, not an id list (RGA) bzr revid: tde@openerp.com-20120221142126-dzr4um7tfq1knxcv --- addons/mail/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index e0a42f3cfe7..b3592e0954e 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -537,7 +537,7 @@ class mail_thread(osv.osv): subscription_obj = self.pool.get('mail.subscription') sub_ids = subscription_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) subs = subscription_obj.read(cr, uid, sub_ids, context=context) - return [sub['user_id'] for sub in subs] + return [sub['user_id'][0] for sub in subs] def message_get_subscribers(self, cr, uid, ids, context=None): user_ids = self.message_get_subscribers_ids(cr, uid, ids, context=context) From 413df331044c61f8015cb9f580caaf424346dbdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 21 Feb 2012 16:39:03 +0100 Subject: [PATCH 048/691] [IMP] Removed space in a note. bzr revid: tde@openerp.com-20120221153903-px8wbaia3y9h4rvg --- addons/hr_holidays/hr_holidays.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index a8573b9bf7c..82d3d7d51cb 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -361,7 +361,7 @@ class hr_holidays(osv.osv): def create_notificate(self, cr, uid, ids, context=None): obj = self.browse(cr, uid, ids, context=context)[0] self.message_append_note(cr, uid, ids, _('System notification'), - _("""The %s request '%s' has been created and is in draft mode. In this mode, it can be modified freely. + _("""The %s request '%s' has been created and is in draft mode. In this mode, it can be modified freely. \ Click on Confirm to confirm your request and ask for its validation by the managers.""") % ('leave' if obj.type == 'remove' else 'allocation', obj.name), type='notification', context=context) return True From 7429f3bfb6797b1bdd97e05afdd5992a3bd320ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 21 Feb 2012 16:39:42 +0100 Subject: [PATCH 049/691] [IMP] Slighty improved wall widget. bzr revid: tde@openerp.com-20120221153942-mue1h18f2fjluf27 --- addons/mail/static/src/css/mail.css | 5 +++++ addons/mail/static/src/js/mail.js | 27 ++++++++++++--------------- addons/mail/static/src/xml/mail.xml | 10 ++++++---- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 0d153ce0c06..be5e8425630 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -5,6 +5,11 @@ padding: 5px 5px 5px 5px; } +.oe_mail_wall_main { + overflow: auto; + padding: 5px 5px 5px 5px; +} + /* 2 columns view */ .oe_mail_main_left { float: left; diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index b9404885b6a..cd2e1f2ac5d 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -34,7 +34,6 @@ openerp.mail = function(session) { }, stop: function () { - console.log('stop'); this._super.apply(this, arguments); }, @@ -134,39 +133,37 @@ openerp.mail = function(session) { start: function() { var self = this; this._super.apply(this, arguments); - console.log(this); - self.$element.find('button.oe_mail_action_comment').bind('click', function () { self.do_comment(); }); - this.ds_msg.call('get_pushed_messages', [[], self.filter_search]).then( - this.proxy('display_records')); + self.$element.find('button.oe_mail_button_comment').bind('click', function () { self.do_comment(); }); + return this.fetch_comments(); }, stop: function () { this._super(); }, - fetch_messages: function () { - console.log('debug--fetch_messages'); - return this.ds_msg.call('get_pushed_messages', []).then( - this.proxy('display_records')); + fetch_comments: function () { + var load_res = this.ds_msg.call('get_pushed_messages', [[this.session.uid]]).then( + this.proxy('display_comments')); + return load_res; }, - display_records: function (records) { - this.$element.find('div.oe_mail_comments').empty(); + display_comments: function (records) { + this.$element.find('div.oe_mail_msg').empty(); var self = this; _(records).each(function (record) { + console.log(record); var template = 'ThreadMsgView'; var render_res = session.web.qweb.render(template, { 'record': record, }); - $('
').html(render_res).appendTo(self.$element.find('div.oe_mail_comments')); + $('
').html(render_res).appendTo(self.$element.find('div.oe_mail_msg')); }); -// this.timeout = setTimeout(this.proxy('fetch_messages'), 5000); }, do_comment: function () { var body_text = this.$element.find('textarea').val(); - return this.ds.call('message_append_note', [[this.view.datarecord.id], 'Reply comment', body_text, type='comment']).then( - this.proxy('fetch_messages')); + return this.ds_msg.call('create', [{'subject': 'Status tweet', 'model': 'res.users', 'body_text': body_text, 'type': 'comment'}]).then( + this.proxy('fetch_comments')); }, }); }; diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index 50e73f10326..ff69ef4c29f 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -47,12 +47,14 @@
-
+
-
- +
+
-
+
+
+
From babd47b963aa421c5b92624a485eb509ea7e970e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 22 Feb 2012 10:09:23 +0100 Subject: [PATCH 050/691] [IMP] Notification push moved from mail.message to mail.thread to use message_get_subscribers method. Also added a temporary debug log on message.create method, to help tracking messages not using mail.thread. bzr revid: tde@openerp.com-20120222090923-1h6wx3bkwr5ngt4d --- addons/mail/mail_message.py | 31 +++++++++---------------------- addons/mail/mail_thread.py | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 03eb57bfd0f..87e73dbb471 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -197,31 +197,18 @@ class mail_message(osv.osv): #------------------------------------------------------ def create(self, cr, uid, vals, context=None): - # OpenSocial: notifications do not come from any user but from system - if vals.get('type') == 'notification': vals['user_id'] = False - need_action_pushed = False + # temporary log directly created messages (to debug OpenSocial) + if not 'mail.thread' in context: + _logger.warning('Creating message without using mail.thread API') + _logger.warning('Message details: %s', str(vals)) msg_id = super(mail_message, self).create(cr, uid, vals, context) - # push the message to suscribed users - subscription_obj = self.pool.get('mail.subscription') - notification_obj = self.pool.get('mail.notification') - # not pure-email: check for subscriptions - if not 'need_action_user_id' in vals: vals['need_action_user_id'] = False - if not 'model' in vals: vals['model'] = False - if not 'res_id' in vals: vals['res_id'] = 0 - sub_ids = subscription_obj.search(cr, uid, ['&', - ('res_model', '=', vals['model']), - ('res_id', '=', vals['res_id'])], context=context) - subs = subscription_obj.browse(cr, uid, sub_ids, context=context) - for sub in subs: - notification_obj.create(cr, uid, {'user_id': sub.user_id.id, 'message_id': msg_id}, context=context) - if vals['need_action_user_id'] == sub.user_id: need_action_pushed = True - # push to need_action_user_id if user does not follow the object - if vals['need_action_user_id'] and not need_action_pushed: - notification_obj.create(cr, uid, {'user_id': vals['need_action_user_id'], 'message_id': msg_id}, context=context) return msg_id def get_pushed_messages(self, cr, uid, ids, filter_search=False, context=None): - """Wall: get messages to display""" + """OpenSocial: wall: get messages to display (=pushed notifications) + :param filter_search: TODO + :return: dict { res_model: { res_id: [pushed message list] }} + """ notification_obj = self.pool.get('mail.notification') notification_ids = notification_obj.search(cr, uid, [('user_id', '=', uid)], context=context) notifications = notification_obj.browse(cr, uid, notification_ids, context=context) @@ -230,7 +217,7 @@ class mail_message(osv.osv): msgs = self.read(cr, uid, msg_ids, context=context) print msgs - # TODO / REMARK: classify based on res_model / res_id to have a 1_level hierarchy ? + # sort return msgs diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index b3592e0954e..89273389dd2 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -72,6 +72,33 @@ class mail_thread(osv.osv): #------------------------------------------------------ # Generic message api #------------------------------------------------------ + + def message_create(self, cr, uid, ids, vals, context=None): + """OpenSocial: wrapper of mail.message create method + - creates the mail.message + - push the message to subscribed users""" + subscription_obj = self.pool.get('mail.subscription') + notification_obj = self.pool.get('mail.notification') + + # notifications do not come from any user, but from system + if vals.get('type') == 'notification': vals['user_id'] = False + if not 'need_action_user_id' in vals: vals['need_action_user_id'] = False + if not 'model' in vals: vals['model'] = False + if not 'res_id' in vals: vals['res_id'] = 0 + need_action_pushed = False + + msg_id = self.pool.get('mail.message').create(cr, uid, vals, context=context) + + # push the message to suscribed users + users = self.message_get_subscribers(cr, uid, ids, context=context) + for user in users: + notification_obj.create(cr, uid, {'user_id': user['id'], 'message_id': msg_id}, context=context) + if vals['need_action_user_id'] == user['id']: need_action_pushed = True + # push to need_action_user_id if user does not follow the object + if vals['need_action_user_id'] and not need_action_pushed: + notification_obj.create(cr, uid, {'user_id': vals['need_action_user_id'], 'message_id': msg_id}, context=context) + return msg_id + def message_capable_models(self, cr, uid, context=None): ret_dict = {} for model_name in self.pool.obj_list(): @@ -197,7 +224,9 @@ class mail_thread(osv.osv): 'reply_to': reply_to, 'original': original, } - mail_message.create(cr, uid, data, context=context) + #mail_message.create(cr, uid, data, context=context) + context['mail.thread'] = True + self.message_create(cr, uid, [thread.id], data, context=context) return True def message_append_dict(self, cr, uid, ids, msg_dict, context=None): @@ -533,14 +562,14 @@ class mail_thread(osv.osv): # Subscription mechanism #------------------------------------------------------ - def message_get_subscribers_ids(self, cr, uid, ids, context=None): + def _message_get_subscribers_ids(self, cr, uid, ids, context=None): subscription_obj = self.pool.get('mail.subscription') sub_ids = subscription_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) subs = subscription_obj.read(cr, uid, sub_ids, context=context) return [sub['user_id'][0] for sub in subs] def message_get_subscribers(self, cr, uid, ids, context=None): - user_ids = self.message_get_subscribers_ids(cr, uid, ids, context=context) + user_ids = self._message_get_subscribers_ids(cr, uid, ids, context=context) users = self.pool.get('res.users').read(cr, uid, user_ids, context=context) return users From acb592d84b9710bd563df76c8c822031344bf22e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 22 Feb 2012 10:58:12 +0100 Subject: [PATCH 051/691] [IMP] Automatically subscribe the message writer to the related object. bzr revid: tde@openerp.com-20120222095812-mor2qolqjqzm188q --- addons/mail/mail_thread.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 89273389dd2..634ac3525a0 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -76,6 +76,7 @@ class mail_thread(osv.osv): def message_create(self, cr, uid, ids, vals, context=None): """OpenSocial: wrapper of mail.message create method - creates the mail.message + - automatically subscribe the message writer if not already done - push the message to subscribed users""" subscription_obj = self.pool.get('mail.subscription') notification_obj = self.pool.get('mail.notification') @@ -89,6 +90,11 @@ class mail_thread(osv.osv): msg_id = self.pool.get('mail.message').create(cr, uid, vals, context=context) + # automatically subscribe the writer of the message if not subscribed + if vals['user_id']: + if not self.message_is_subscriber(cr, uid, ids, context=context): + self.message_subscribe(cr, uid, ids, context=context) + # push the message to suscribed users users = self.message_get_subscribers(cr, uid, ids, context=context) for user in users: @@ -574,11 +580,12 @@ class mail_thread(osv.osv): return users def message_is_subscriber(self, cr, uid, ids, context=None): + # TODO: use message_get_subscribers ? as all subscriptions are in mail.subscription table, not necessary subscription_obj = self.pool.get('mail.subscription') sub_ids = subscription_obj.search(cr, uid, ['&', '&', ('res_model', '=', self._name), ('res_id', 'in', ids), ('user_id', '=', uid)], context=context) if len(sub_ids) > 1: - print 'cacaprout error !' + pass # TODO return True if sub_ids else False def message_subscribe(self, cr, uid, ids, user_ids = None, context=None): From bfc8e5e86671a67cf03d8d570058800ee2e29259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 22 Feb 2012 10:59:50 +0100 Subject: [PATCH 052/691] [IMP] hr_holidays: propagated changes in subscription mechanism. Also cleaned messages. bzr revid: tde@openerp.com-20120222095950-wnx9qfta5dh4had5 --- addons/hr_holidays/hr_holidays.py | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index 82d3d7d51cb..78db0dc7063 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -359,30 +359,20 @@ class hr_holidays(osv.osv): # ----------------------------- def create_notificate(self, cr, uid, ids, context=None): - obj = self.browse(cr, uid, ids, context=context)[0] - self.message_append_note(cr, uid, ids, _('System notification'), - _("""The %s request '%s' has been created and is in draft mode. In this mode, it can be modified freely. \ - Click on Confirm to confirm your request and ask for its validation by the managers.""") - % ('leave' if obj.type == 'remove' else 'allocation', obj.name), type='notification', context=context) + for obj in self.browse(cr, uid, ids, context=context): + # add the employee and its manager if specified to the subscribed users + self.message_subscribe(cr, uid, ids, [obj.employee_id.user_id.id], context=context) + if obj.employee_id.parent_id: + self.message_subscribe(cr, uid, ids, [obj.employee_id.parent_id.user_id.id], context=context) + self.message_append_note(cr, uid, ids, _('System notification'), + _("The %s request '%s' has been created and is waiting confirmation") + % ('leave' if obj.type == 'remove' else 'allocation', obj.name), type='notification', context=context) return True - def message_get_subscribers(self, cr, uid, ids, context=None): - """OpenChatter: override message_get_subscribers to add : - - employee related user - - employee manager user, if it exists""" - users = super(hr_holidays, self).message_get_subscribers(cr, uid, ids, context=context) - user_ids = [] - for holidays in self.browse(cr, uid, ids, context=context): - user_ids.append(holidays.user_id.id) - if holidays.employee_id.parent_id: - user_ids.append(holidays.employee_id.parent_id.user_id.id) - users += self.pool.get('res.users').read(cr, uid, user_ids, context=context) - return users - def holidays_confirm_notificate(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids): self.message_append_note(cr, uid, [obj.id], _('System notification'), - _("The %s request '%s' has been confirmed. It is now waiting for validation by the manager.") + _("The %s request '%s' has been confirmed and is waiting for validation by the manager.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name,), type='notification', need_action_user_id = obj.employee_id.parent_id.user_id.id if obj.employee_id.parent_id else False) @@ -391,7 +381,7 @@ class hr_holidays(osv.osv): self.message_mark_done(cr, uid, [obj.id], context=context) if obj.holiday_status_id.double_validation: self.message_append_note(cr, uid, [obj.id], _('System notification'), - _("The %s request '%s' has been validated. A second validation of your request is necessary and is now pending.") + _("The %s request '%s' has been validated. A second validation is necessary and is now pending.") % ('leave' if obj.type == 'remove' else 'allocation', obj.name), type='notification', context=context) else: self.message_append_note(cr, uid, [obj.id], _('System notification'), From b0a1a7e24ae70e1a0d71b9f36ff3a9e4f7f139c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 22 Feb 2012 11:12:16 +0100 Subject: [PATCH 053/691] [FIX] added user_id when posting a tweet from the wall bzr revid: tde@openerp.com-20120222101216-9xpo3c0gj1ickigl --- addons/mail/mail_message.py | 6 ++---- addons/mail/static/src/js/mail.js | 5 +++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 87e73dbb471..f6d7d2c863c 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -214,11 +214,9 @@ class mail_message(osv.osv): notifications = notification_obj.browse(cr, uid, notification_ids, context=context) msg_ids = [notification.message_id.id for notification in notifications] - msgs = self.read(cr, uid, msg_ids, context=context) - print msgs + msgs = self.read(cr, uid, msg_ids, context=context) + # sort: TODO - # sort - return msgs #------------------------------------------------------ diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index cd2e1f2ac5d..bd3021e9f1f 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -162,8 +162,9 @@ openerp.mail = function(session) { do_comment: function () { var body_text = this.$element.find('textarea').val(); - return this.ds_msg.call('create', [{'subject': 'Status tweet', 'model': 'res.users', 'body_text': body_text, 'type': 'comment'}]).then( - this.proxy('fetch_comments')); + return this.ds_msg.call('create', [ + {'subject': 'Status tweet', 'model': 'res.users', 'body_text': body_text, 'type': 'comment', 'res_id': this.session.uid, 'user_id': this.session.uid} + ]).then(this.proxy('fetch_comments')); }, }); }; From 9ced116caa379f2b876912a0a638f61b51d5becd Mon Sep 17 00:00:00 2001 From: "Bhumi Thakkar (Open ERP)" Date: Wed, 22 Feb 2012 16:36:16 +0530 Subject: [PATCH 054/691] [IMP] Threadview in crm. bzr revid: bth@tinyerp.com-20120222110616-i4sz2b1630ehzqel --- addons/crm/crm_lead_view.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index 3fc6aff1536..01020ac213c 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -195,6 +195,7 @@ + @@ -589,6 +590,7 @@ + From bb1b6fe1766ac240e2d6e0154bd0d6dcd4e714e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 22 Feb 2012 12:59:24 +0100 Subject: [PATCH 055/691] [ADD] res_users: added res_users.py file, making res.users in heriting from mail.thread. This is necessary to use mail.thread API on users (for tweets). bzr revid: tde@openerp.com-20120222115924-i55twzupuuzuc3gl --- addons/mail/__init__.py | 1 + addons/mail/res_users.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 addons/mail/res_users.py diff --git a/addons/mail/__init__.py b/addons/mail/__init__.py index 64339fcb9c0..2474c321946 100644 --- a/addons/mail/__init__.py +++ b/addons/mail/__init__.py @@ -23,6 +23,7 @@ import mail_message import mail_thread import mail_group import mail_subscription +import res_users import res_partner import wizard diff --git a/addons/mail/res_users.py b/addons/mail/res_users.py new file mode 100644 index 00000000000..1c650ab1a34 --- /dev/null +++ b/addons/mail/res_users.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2009-Today OpenERP SA () +# +# 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 +# +############################################################################## + +from osv import osv + +class res_users(osv.osv): + _name = 'res.users' + _inherit = ['res.users', 'mail.thread'] + + def create(self, cr, uid, data, context=None): + user_id = super(res_users, self).create(cr, uid, data, context=context) + # make user follow itself + self.message_subscribe(cr, uid, [user_id], [user_id], context=context) + return user_id + From d9a3b4b2900a477810c850e80b5cfb6fcbb5407f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 22 Feb 2012 14:35:01 +0100 Subject: [PATCH 056/691] [REF] Cleaned mail.message get_pushed_messages method bzr revid: tde@openerp.com-20120222133501-it9li0lh8fwvuk4e --- addons/mail/mail_message.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index f6d7d2c863c..9391a931774 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -207,16 +207,13 @@ class mail_message(osv.osv): def get_pushed_messages(self, cr, uid, ids, filter_search=False, context=None): """OpenSocial: wall: get messages to display (=pushed notifications) :param filter_search: TODO - :return: dict { res_model: { res_id: [pushed message list] }} + :return: list of mail.messages, unsorted """ notification_obj = self.pool.get('mail.notification') notification_ids = notification_obj.search(cr, uid, [('user_id', '=', uid)], context=context) notifications = notification_obj.browse(cr, uid, notification_ids, context=context) - msg_ids = [notification.message_id.id for notification in notifications] - msgs = self.read(cr, uid, msg_ids, context=context) - # sort: TODO - + msgs = self.read(cr, uid, msg_ids, context=context) return msgs #------------------------------------------------------ From 167f39807cd0478ca042aa550eb80c80e4954450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 22 Feb 2012 15:03:18 +0100 Subject: [PATCH 057/691] [IMP] mail.thread: get_subscribed_users returns only necessary fields bzr revid: tde@openerp.com-20120222140318-8trixmwfvgus00x4 --- addons/mail/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 634ac3525a0..ee3270ca872 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -576,7 +576,7 @@ class mail_thread(osv.osv): def message_get_subscribers(self, cr, uid, ids, context=None): user_ids = self._message_get_subscribers_ids(cr, uid, ids, context=context) - users = self.pool.get('res.users').read(cr, uid, user_ids, context=context) + users = self.pool.get('res.users').read(cr, uid, user_ids, fields=['id', 'name', 'avatar_mini'], context=context) return users def message_is_subscriber(self, cr, uid, ids, context=None): From 1bc3f0cec4353e558ef47cf29bcc7b974d4194b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 22 Feb 2012 15:04:03 +0100 Subject: [PATCH 058/691] [IMP] Wall: pushed message are now displayed in conversation, with a 1-level hierarchy based on source record. Wall and Thread: added support for user image. bzr revid: tde@openerp.com-20120222140403-fbjisr0u96jml5zv --- addons/mail/static/src/css/mail.css | 19 +++++---- addons/mail/static/src/js/mail.js | 61 +++++++++++++++++++++++------ addons/mail/static/src/xml/mail.xml | 45 +++++++++++++++------ 3 files changed, 92 insertions(+), 33 deletions(-) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index be5e8425630..9f4d8440205 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -50,24 +50,23 @@ .oe_mail_msg { } -/*.oe_mail_msg:after { - content: ""; - display: block; - clear: both; -}*/ - .oe_mail_comment { white-space: normal; margin-bottom: 5px; } +.oe_mail_comment:after { + content: ""; + display: block; + clear: both; +} + .oe_mail_msg_image { float: left; width: 14%; } .oe_mail_msg_image img { - width: 80%; margin-left: 10%; } @@ -105,3 +104,9 @@ .oe_mail_followers_vignette img { width: 80%; } + +/* Wall CSS */ +.oe_mail_thread_content div.oe_mail_comment { + margin-left: 5%; +} + diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index bd3021e9f1f..daf15e41d35 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -70,6 +70,7 @@ openerp.mail = function(session) { this.$element.find('div.oe_mail_msg').empty(); var self = this; _(records).each(function (record) { + record.mini_url = self.thread_get_mini('res.users', 'avatar_mini', record.user_id[0]); var template = 'ThreadMsgView'; var render_res = session.web.qweb.render(template, { 'record': record, @@ -77,14 +78,14 @@ openerp.mail = function(session) { $('
').html(render_res).appendTo(self.$element.find('div.oe_mail_msg')); }); }, - + display_followers: function (records) { this.$element.find('div.oe_mail_followers').empty(); var self = this; _(records).each(function (record) { -//
- //$('
').text(record.user_id[1]).appendTo(self.$element.find('div.oe_mail_followers')); - $('
').text(record.name).appendTo(self.$element.find('div.oe_mail_followers')); + $('
').html( + '' + record.name + '' + ).appendTo(self.$element.find('div.oe_mail_followers')); }); }, @@ -113,6 +114,12 @@ openerp.mail = function(session) { do_toggle_followers: function () { this.$element.find('div.oe_mail_followers').toggle(); }, + + thread_get_mini: function(model, field, id) { + id = id || ''; + var url = this.session.prefix + '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + id; + return url; + }, }); /* Add WallView widget to registry */ @@ -128,6 +135,7 @@ openerp.mail = function(session) { this.filter_search = params['filter_search']; /* DataSets */ this.ds_msg = new session.web.DataSet(this, 'mail.message'); + this.ds_users = new session.web.DataSet(this, 'res.users'); }, start: function() { @@ -149,22 +157,49 @@ openerp.mail = function(session) { display_comments: function (records) { this.$element.find('div.oe_mail_msg').empty(); + sorted_records = this.sort_comments(records); var self = this; - _(records).each(function (record) { - console.log(record); - var template = 'ThreadMsgView'; - var render_res = session.web.qweb.render(template, { - 'record': record, + _(sorted_records).each(function (rec_models, model) { // each model + _(rec_models).each(function (record_id, id) { // each record + var template = 'WallThreadView'; + var render_res = session.web.qweb.render(template, { + 'record_model': model, + 'record_id': id, }); - $('
').html(render_res).appendTo(self.$element.find('div.oe_mail_msg')); + $('
').html(render_res).appendTo(self.$element.find('div.oe_mail_msg')); + _(record_id).each(function (record) { // each record + record.mini_url = self.thread_get_mini('res.users', 'avatar_mini', record.user_id[0]); + var template = 'ThreadMsgView'; + var render_res = session.web.qweb.render(template, { + 'record': record, + }); + $('
').html(render_res).appendTo(self.$element.find('div.oe_mail_thread_content:last')); + }); + }); }); }, + sort_comments: function (records) { + sorted_comments = {}; + _(records).each(function (record) { + if (! (record.model in sorted_comments)) { sorted_comments[record.model] = {}; } + if (! (record.res_id in sorted_comments[record.model])) { + sorted_comments[record.model][record.res_id] = []; } + sorted_comments[record.model][record.res_id].push(record); + }); + return sorted_comments; + }, + do_comment: function () { var body_text = this.$element.find('textarea').val(); - return this.ds_msg.call('create', [ - {'subject': 'Status tweet', 'model': 'res.users', 'body_text': body_text, 'type': 'comment', 'res_id': this.session.uid, 'user_id': this.session.uid} - ]).then(this.proxy('fetch_comments')); + return this.ds_users.call('message_append_note', [[this.session.uid], 'Tweet', body_text, type='comment']).then( + this.proxy('fetch_comments')); + }, + + thread_get_mini: function(model, field, id) { + id = id || ''; + var url = this.session.prefix + '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + id; + return url; }, }); }; diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index ff69ef4c29f..755357b7da3 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -25,9 +25,39 @@
- + +
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + +
+ Discussion about document (id: ) +
+
+
+
+ -
Image
+
+ +

@@ -46,16 +76,5 @@

- -
-
-
- -
-
-
-
-
-
From 6671d25523af5fdb9b9da08bacce7033772a1af4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 22 Feb 2012 15:48:35 +0100 Subject: [PATCH 059/691] [IMP] ThreadView: moved follow/unfollow action on the right; see followers now has its value toggling when choosing to display or hide followers; comment textare now displays as a comment, i.e. it has user avatar on the left and is aligned with comments bzr revid: tde@openerp.com-20120222144835-w8jfscffigaggr6p --- addons/mail/static/src/css/mail.css | 2 +- addons/mail/static/src/js/mail.js | 26 ++++++++++++++++++++++---- addons/mail/static/src/xml/mail.xml | 22 ++++++++++++++-------- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 9f4d8440205..ed824071f0f 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -31,7 +31,7 @@ } .oe_mail_button_follow, .oe_mail_button_unfollow, .oe_mail_button_followers { - width: 100px; + width: 120px; } .oe_mail_button_comment { diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index daf15e41d35..fe29fd8d139 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -14,10 +14,12 @@ openerp.mail = function(session) { form_template: 'ThreadView', init: function() { - this.follow_state = 0; + this.is_sub = 0; + this.see_sub = 1; this._super.apply(this, arguments); /* DataSets */ this.ds = new session.web.DataSet(this, this.view.model); + this.ds_users = new session.web.DataSet(this, 'res.users'); }, start: function() { @@ -46,14 +48,21 @@ openerp.mail = function(session) { if (! this.view.datarecord.id) { return; } /* find wich (un)follow buttons to show */ var call_res = this.ds.call('message_is_subscriber', [[this.view.datarecord.id]]).then(function (records) { - if (records == true) { self.follow_state = 1; self.$element.find('button.oe_mail_button_unfollow').show(); } - else { self.follow_state = 0; self.$element.find('button.oe_mail_button_follow').show(); } + if (records == true) { self.is_sub = 1; self.$element.find('button.oe_mail_button_unfollow').show(); } + else { self.is_sub = 0; self.$element.find('button.oe_mail_button_follow').show(); } }); + console.log(this); /* fetch comments and subscribers */ + this.fetch_current_user(); this.fetch_subscribers(); return this.fetch_comments(); }, + fetch_current_user: function () { + return this.ds_users.read_ids([this.session.uid], ['id', 'name', 'avatar_mini']).then( + this.proxy('display_current_user')); + }, + fetch_comments: function () { var load_res = this.ds.call('message_load', [[this.view.datarecord.id]]).then( this.proxy('display_comments')); @@ -66,6 +75,12 @@ openerp.mail = function(session) { return follow_res; }, + display_current_user: function (records) { + $('
').html( + '' + records[0].name + '' + ).appendTo(this.$element.find('div.oe_mail_msg_image')); + }, + display_comments: function (records) { this.$element.find('div.oe_mail_msg').empty(); var self = this; @@ -106,12 +121,15 @@ openerp.mail = function(session) { }, do_toggle_follow: function () { - this.follow_state = 1 - this.follow_state; + this.is_sub = 1 - this.is_sub; this.$element.find('button.oe_mail_button_unfollow').toggle(); this.$element.find('button.oe_mail_button_follow').toggle(); }, do_toggle_followers: function () { + this.see_sub = 1 - this.see_sub; + if (this.see_sub == 1) { this.$element.find('button.oe_mail_button_followers').html('Hide followers'); } + else { this.$element.find('button.oe_mail_button_followers').html('Display followers'); } this.$element.find('div.oe_mail_followers').toggle(); }, diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index 755357b7da3..79e421cc559 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -4,13 +4,15 @@
OpenSocial
-
- - -
-
-
- +
+
+
+
+
+
+ +
+
@@ -18,8 +20,12 @@
+
+ + +
- +
From bf50057d22d0771ac59f4d57f4c8a63ba4851ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 22 Feb 2012 15:58:00 +0100 Subject: [PATCH 060/691] [IMP] ThreadView: image left of post comment area is not refreshed in each set_value, only initialized bzr revid: tde@openerp.com-20120222145800-rfqkznqxcf3a22ok --- addons/mail/static/src/js/mail.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index fe29fd8d139..2ef72d0b816 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -16,6 +16,7 @@ openerp.mail = function(session) { init: function() { this.is_sub = 0; this.see_sub = 1; + this.user_init = 0; this._super.apply(this, arguments); /* DataSets */ this.ds = new session.web.DataSet(this, this.view.model); @@ -53,7 +54,10 @@ openerp.mail = function(session) { }); console.log(this); /* fetch comments and subscribers */ - this.fetch_current_user(); + if (this.user_init == 0) { + this.fetch_current_user(); + this.user_init = 1; + } this.fetch_subscribers(); return this.fetch_comments(); }, From 44e6b0f079edccf0ad7f21d84463a83a6df57589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 22 Feb 2012 16:26:43 +0100 Subject: [PATCH 061/691] [IMP] Improved display of avatars bzr revid: tde@openerp.com-20120222152643-cdiyr0klegnt9sxd --- addons/mail/static/src/css/mail.css | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index ed824071f0f..3f9fe3149d3 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -63,11 +63,25 @@ .oe_mail_msg_image { float: left; - width: 14%; + width: 100px; + height: 100px; + text-align: center; + overflow: hidden; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + -o-border-radius: 3px; + -ms-border-radius: 3px; + border-radius: 3px; + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); + -o-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); + -box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); } .oe_mail_msg_image img { - margin-left: 10%; + width: 100px; + height: auto; + clip: rect(10px, 100px, 110px, 0px); } .oe_mail_msg_content { From 99a3eeed4cb3319bb4066a57973c892ea82633eb Mon Sep 17 00:00:00 2001 From: "Bhumi Thakkar (Open ERP)" Date: Thu, 23 Feb 2012 16:16:41 +0530 Subject: [PATCH 062/691] [IMP] replace *args with context=None in crm.py and crm_lead.py,craeate methods in crm.py and crm_lead.py file _case_open_notification,_case_close_notification,_case_cancel_notification,_case_pending_notification,_case_escalate_notification,remove message_ids field from crm_lead.py file and crm_lead_view.xml file,add type : 'email' in 'schedule_with_attach' method in mail_message.py file bzr revid: bth@tinyerp.com-20120223104641-ej8bbbzgwt4v670h --- addons/crm/crm.py | 57 +++++++++++------ addons/crm/crm_lead.py | 117 +++++++++++++++++++++-------------- addons/crm/crm_lead_view.xml | 11 ---- addons/mail/mail_message.py | 1 + 4 files changed, 108 insertions(+), 78 deletions(-) diff --git a/addons/crm/crm.py b/addons/crm/crm.py index 7775e442df7..292169404a3 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -127,7 +127,7 @@ class crm_case_section(osv.osv): def name_get(self, cr, uid, ids, context=None): """Overrides orm name_get method""" - if not isinstance(ids, list) : + if not isinstance(ids, list) : ids = [ids] res = [] if not ids: @@ -258,7 +258,9 @@ class crm_base(object): data.update(self.onchange_partner_address_id(cr, uid, ids, addr['contact'])['value']) return {'value': data} - def case_open(self, cr, uid, ids, *args): + + + def case_open(self, cr, uid, ids, context=None): """Opens Case :param ids: List of case Ids """ @@ -268,11 +270,12 @@ class crm_base(object): if not case.user_id: data['user_id'] = uid self.write(cr, uid, case.id, data) - + self._case_open_notification(case, context=context) self._action(cr, uid, cases, 'open') + return True - def case_close(self, cr, uid, ids, *args): + def case_close(self, cr, uid, ids, context=None): """Closes Case :param ids: List of case Ids """ @@ -283,7 +286,7 @@ class crm_base(object): self._action(cr, uid, cases, 'done') return True - def case_cancel(self, cr, uid, ids, *args): + def case_cancel(self, cr, uid, ids, context=None): """Cancels Case :param ids: List of case Ids """ @@ -294,7 +297,7 @@ class crm_base(object): self._action(cr, uid, cases, 'cancel') return True - def case_pending(self, cr, uid, ids, *args): + def case_pending(self, cr, uid, ids, context=None): """Marks case as pending :param ids: List of case Ids """ @@ -304,7 +307,7 @@ class crm_base(object): self._action(cr, uid, cases, 'pending') return True - def case_reset(self, cr, uid, ids, *args): + def case_reset(self, cr, uid, ids, context=None): """Resets case as draft :param ids: List of case Ids """ @@ -325,10 +328,10 @@ class crm_base(object): return rule_obj._action(cr, uid, rule_ids, cases, scrit=scrit, context=context) class crm_case(crm_base): - """ A simple python class to be used for common functions + """ A simple python class to be used for common functions Object that inherit from this class should inherit from mailgate.thread And need a stage_id field - And object that inherit (orm inheritance) from a class the overwrite copy + And object that inherit (orm inheritance) from a class the overwrite copy """ def stage_find(self, cr, uid, section_id, domain=[], order='sequence'): @@ -389,8 +392,22 @@ class crm_case(crm_base): default.update({ 'date_open': False }) return super(crm_case, self).copy(cr, uid, id, default, context=context) + def _case_open_notification(self, case, context=None): + return True - def case_open(self, cr, uid, ids, *args): + def _case_close_notification(self, case, context=None): + return True + + def _case_cancel_notification(self, case, context=None): + return True + + def _case_pending_notification(self, case, context=None): + return True + + def _case_escalate_notification(self, case, context=None): + return True + + def case_open(self, cr, uid, ids, context=None): """Opens Case""" cases = self.browse(cr, uid, ids) for case in cases: @@ -398,10 +415,11 @@ class crm_case(crm_base): if not case.user_id: data['user_id'] = uid self.write(cr, uid, case.id, data) + self._case_open_notification(case, context=context) self._action(cr, uid, cases, 'open') return True - def case_close(self, cr, uid, ids, *args): + def case_close(self, cr, uid, ids, context=None): """Closes Case""" cases = self.browse(cr, uid, ids) cases[0].state # to fill the browse record cache @@ -411,10 +429,11 @@ class crm_case(crm_base): # # We use the cache of cases to keep the old case state # + self._case_close_notification(cases, context=context) self._action(cr, uid, cases, 'done') return True - def case_escalate(self, cr, uid, ids, *args): + def case_escalate(self, cr, uid, ids, context=None): """Escalates case to parent level""" cases = self.browse(cr, uid, ids) for case in cases: @@ -428,33 +447,33 @@ class crm_case(crm_base): raise osv.except_osv(_('Error !'), _('You can not escalate, you are already at the top level regarding your sales-team category.')) self.write(cr, uid, [case.id], data) cases = self.browse(cr, uid, ids) + self._case_escalate_notification(cases, context=context) self._action(cr, uid, cases, 'escalate') return True - def case_cancel(self, cr, uid, ids, *args): + def case_cancel(self, cr, uid, ids, context=None): """Cancels Case""" cases = self.browse(cr, uid, ids) cases[0].state # to fill the browse record cache self.write(cr, uid, ids, {'state': 'cancel', 'active': True}) + self._case_cancel_notification(cases, context=context) self._action(cr, uid, cases, 'cancel') - for case in cases: - message = _("The case '%s' has been cancelled.") % (case.name,) - self.log(cr, uid, case.id, message) return True - def case_pending(self, cr, uid, ids, *args): + def case_pending(self, cr, uid, ids, context=None): """Marks case as pending""" cases = self.browse(cr, uid, ids) cases[0].state # to fill the browse record cache self.write(cr, uid, ids, {'state': 'pending', 'active': True}) + self._case_pending_notification(cases, context=context) self._action(cr, uid, cases, 'pending') return True - def case_reset(self, cr, uid, ids, *args): + def case_reset(self, cr, uid, ids, context=None): """Resets case as draft""" state = 'draft' - if 'crm.phonecall' in args: + if 'crm.phonecall' in context: #TO fix: move into crm_phonecall.py? state = 'open' cases = self.browse(cr, uid, ids) cases[0].state # to fill the browse record cache diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index b17fa31ac91..4a3ae69fba7 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -189,7 +189,6 @@ class crm_lead(crm_case, osv.osv): \nIf the case is in progress the state is set to \'Open\'.\ \nWhen the case is over, the state is set to \'Done\'.\ \nIf the case needs to be reviewed then the state is set to \'Pending\'.'), - 'message_ids': fields.one2many('mail.message', 'res_id', 'Messages', domain=[('model','=',_name)]), 'subjects': fields.function(_get_email_subject, fnct_search=_history_search, string='Subject of Email', type='char', size=64), @@ -266,75 +265,97 @@ class crm_lead(crm_case, osv.osv): def stage_find_won(self, cr, uid, section_id): return self.stage_find_percent(cr, uid, 100.0, section_id) - def case_open(self, cr, uid, ids, *args): - for l in self.browse(cr, uid, ids): - # When coming from draft override date and stage otherwise just set state - if l.state == 'draft': - if l.type == 'lead': - message = _("The lead '%s' has been opened.") % l.name - elif l.type == 'opportunity': - message = _("The opportunity '%s' has been opened.") % l.name - else: - message = _("The case '%s' has been opened.") % l.name - self.log(cr, uid, l.id, message) - value = {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')} - self.write(cr, uid, [l.id], value) - if l.type == 'opportunity' and not l.stage_id: - stage_id = self.stage_find(cr, uid, l.section_id.id or False, [('sequence','>',0)]) - if stage_id: - self.stage_set(cr, uid, [l.id], stage_id) - res = super(crm_lead, self).case_open(cr, uid, ids, *args) + def _case_open_notification(self, lead, context=None): + if lead.state != 'draft': + return False + if lead.type == 'lead': + message = _("The lead %s has been opened and its state is now in progress. Salesman %s can now set this lead as pending, close it to mark it as done, or cancel it. If there is an opportunity to create from this lead, click on Convert to Opportunity.") % (lead.name, lead.user_id.name) + elif lead.type == 'opportunity': + message = _("The opportunity %s has been opened.") % lead.name + else: + message = _("The case %s has been opened.") % lead.name + lead.message_append_note('' ,message, need_action_user_id=lead.user_id.id) + + def _case_close_notification(self, lead, context=None): + if lead[0].type == 'lead': + message = _("The lead %s has been closed.") % lead[0].name + else: + message = _("The case %s has been closed.") % lead[0].name + + lead[0].message_append_note('' ,message, need_action_user_id=lead[0].user_id.id) + + def _case_mark_lost_notification(self, lead, context=None): + message = _("The opportunity %s has been marked as lost.") % lead.name + lead.message_append_note('' ,message, need_action_user_id=lead.user_id.id) + + def _case_mark_won_notification(self, lead, context=None): + message = _("The opportunity %s has been been won.") % lead.name + lead.message_append_note('' ,message, need_action_user_id=lead.user_id.id) + + def _case_cancel_notification(self, lead, context=None): + message = _("The lead %s has been cancelled.") % (lead[0].name) + lead[0].message_append_note('' ,message, need_action_user_id=lead[0].user_id.id) + + def _case_pending_notification(self, case, context=None): + message = _("The lead %s is pending.") % (case[0].name,) + case[0].message_append_note('' ,message, need_action_user_id=case[0].user_id.id) + + def _case_escalate_notification(self, case, context=None): + message = _("The lead %s is pending.") % (case.name,) + case.message_append_note('' ,message, need_action_user_id=case.user_id.id) + + def case_open(self, cr, uid, ids, context=None): + res = super(crm_lead, self).case_open(cr, uid, ids, context) + for lead in self.browse(cr, uid, ids, context=context): + value = {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')} + self.write(cr, uid, [lead.id], value) + if lead.type == 'opportunity' and not lead.stage_id: + stage_id = self.stage_find(cr, uid, lead.section_id.id or False, [('sequence','>',0)]) + if stage_id: + self.stage_set(cr, uid, [lead.id], stage_id) return res - def case_close(self, cr, uid, ids, *args): - res = super(crm_lead, self).case_close(cr, uid, ids, *args) + def case_close(self, cr, uid, ids, context=None): + res = super(crm_lead, self).case_close(cr, uid, ids, context) self.write(cr, uid, ids, {'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')}) - for case in self.browse(cr, uid, ids): - if case.type == 'lead': - message = _("The lead '%s' has been closed.") % case.name - else: - message = _("The case '%s' has been closed.") % case.name - self.log(cr, uid, case.id, message) return res - def case_cancel(self, cr, uid, ids, *args): + def case_cancel(self, cr, uid, ids, context=None): """Overrides cancel for crm_case for setting probability """ - res = super(crm_lead, self).case_cancel(cr, uid, ids, args) + res = super(crm_lead, self).case_cancel(cr, uid, ids, context) self.write(cr, uid, ids, {'probability' : 0.0}) return res - def case_reset(self, cr, uid, ids, *args): + def case_reset(self, cr, uid, ids, context=None): """Overrides reset as draft in order to set the stage field as empty """ - res = super(crm_lead, self).case_reset(cr, uid, ids, *args) + res = super(crm_lead, self).case_reset(cr, uid, ids, context) self.write(cr, uid, ids, {'stage_id': False, 'probability': 0.0}) return res - def case_mark_lost(self, cr, uid, ids, *args): + def case_mark_lost(self, cr, uid, ids, context=None): """Mark the case as lost: state = done and probability = 0% """ - res = super(crm_lead, self).case_close(cr, uid, ids, *args) + res = super(crm_lead, self).case_close(cr, uid, ids, context) self.write(cr, uid, ids, {'probability' : 0.0}) - for l in self.browse(cr, uid, ids): - stage_id = self.stage_find_lost(cr, uid, l.section_id.id or False) + for lead in self.browse(cr, uid, ids): + stage_id = self.stage_find_lost(cr, uid, lead.section_id.id or False) if stage_id: - self.stage_set(cr, uid, [l.id], stage_id) - message = _("The opportunity '%s' has been marked as lost.") % l.name - self.log(cr, uid, l.id, message) + self.stage_set(cr, uid, [lead.id], stage_id) + self._case_mark_lost_notification(lead, context=context) return res - def case_mark_won(self, cr, uid, ids, *args): + def case_mark_won(self, cr, uid, ids, context=None): """Mark the case as lost: state = done and probability = 0% """ - res = super(crm_lead, self).case_close(cr, uid, ids, *args) + res = super(crm_lead, self).case_close(cr, uid, ids, context=None) self.write(cr, uid, ids, {'probability' : 100.0}) - for l in self.browse(cr, uid, ids): - stage_id = self.stage_find_won(cr, uid, l.section_id.id or False) + for lead in self.browse(cr, uid, ids): + stage_id = self.stage_find_won(cr, uid, lead.section_id.id or False) if stage_id: - self.stage_set(cr, uid, [l.id], stage_id) - message = _("The opportunity '%s' has been been won.") % l.name - self.log(cr, uid, l.id, message) + self.stage_set(cr, uid, [lead.id], stage_id) + self._case_mark_won_notification(lead, context=context) return res def set_priority(self, cr, uid, ids, priority): @@ -342,12 +363,12 @@ class crm_lead(crm_case, osv.osv): """ return self.write(cr, uid, ids, {'priority' : priority}) - def set_high_priority(self, cr, uid, ids, *args): + def set_high_priority(self, cr, uid, ids, context=None): """Set lead priority to high """ return self.set_priority(cr, uid, ids, '1') - def set_normal_priority(self, cr, uid, ids, *args): + def set_normal_priority(self, cr, uid, ids, context=None): """Set lead priority to normal """ return self.set_priority(cr, uid, ids, '3') @@ -782,7 +803,7 @@ class crm_lead(crm_case, osv.osv): #re-open values.update(state=crm.AVAILABLE_STATES[1][0]) if not case.date_open: - values['date_open'] = time.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT) + values['date_open'] = time.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT) res = self.write(cr, uid, [case.id], values, context=context) return res diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index 01020ac213c..efeda5ac5fc 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -147,17 +147,6 @@ - - - - - -
-
@@ -79,6 +71,11 @@
+
+
+ +
+
@@ -110,7 +107,7 @@ wrote on
- +

@@ -120,8 +117,16 @@ To:

- +

+ + +
+ +
+
From f48f10bcfa41c03439db4ee91d26be4d39772903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 27 Feb 2012 17:14:09 +0100 Subject: [PATCH 081/691] [REF] Cleaned a bit truncated message code bzr revid: tde@openerp.com-20120227161409-ej67dg04cy2deyjg --- addons/mail/static/src/css/mail.css | 3 ++- addons/mail/static/src/js/mail.js | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index be02336da41..653f71fc040 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -151,7 +151,8 @@ border-bottom: 1px solid #D2D9E7; } -.oe_mail_msg_body { +.oe_mail_msg_body a.reduce, .oe_mail_msg_body_short a.expand { + color: #4E43E7; } .oe_mail_msg_author { diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 1879a117c1f..3d7bca72190 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -95,16 +95,17 @@ openerp.mail = function(session) { record.tr_body_text = self.truncate_string(record.body_text, self.params.char_show_more); record.body_text = self.do_replace_internal_links(record.body_text); if (record.tr_body_text) record.tr_body_text = self.do_replace_internal_links(record.tr_body_text); + // render $(session.web.qweb.render('ThreadMsg', {'record': record})).appendTo(self.$element.find('div.oe_mail_thread_display')); // truncated: hide full-text, show summary, add buttons if (record.tr_body_text) { - var node = self.$element.find('span.oe_mail_msg_body:last').append('Show less'); + var node = self.$element.find('span.oe_mail_msg_body:last').append(' [ ... Show less]'); + self.$element.find('p.oe_mail_msg_p:last').append($('' + record.tr_body_text + ' [ ... Show more]')); + var new_node = self.$element.find('span.oe_mail_msg_body_short:last'); node.hide(); node.find('a:last').click(function() { node.hide(); new_node.show(); return false; }); - self.$element.find('p.oe_mail_msg_p:last').append($('' + record.tr_body_text + 'Show more')); - var new_node = self.$element.find('span.oe_mail_msg_body_short:last'); new_node.find('a:last').click(function() { new_node.hide(); node.show(); return false; }); From 1c100a848cac1939a3fb696c25a13e530e5f9a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 27 Feb 2012 17:21:58 +0100 Subject: [PATCH 082/691] [FIX] Added a class to internal links to delegate an action when clicking bzr revid: tde@openerp.com-20120227162158-q1hyvwxr04scwod7 --- addons/mail/static/src/js/mail.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 3d7bca72190..604f93af2cb 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -10,7 +10,6 @@ openerp.mail = function(session) { /* ThreadDisplay widget: display a thread of comments */ mail.ThreadDisplay = session.web.Widget.extend({ - // QWeb template to use when rendering the object template: 'ThreadDisplay', /** @@ -27,7 +26,6 @@ openerp.mail = function(session) { */ init: function(parent, params) { this._super(parent); - console.log(parent); this.params = params; this.params.limit = this.params.limit || 10; this.params.offset = this.params.offset || 0; @@ -139,7 +137,7 @@ openerp.mail = function(session) { while (regex_res != null) { var login = regex_res[2]; var res_id = 1; - string = string.replace(regex_res[0], '@' + login + ''); + string = string.replace(regex_res[0], '@' + login + ''); regex_res = regex_login.exec(string); } return string; From 83ef71f651885b60ab11da5963b03598ed4a6608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 27 Feb 2012 18:13:23 +0100 Subject: [PATCH 083/691] [REF] Some code cleaning. Hashtag replacement still not working. bzr revid: tde@openerp.com-20120227171323-xvn752llibh66v9w --- addons/mail/static/src/js/mail.js | 100 +++++++++++++++--------------- 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 604f93af2cb..5b83020fdc4 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -31,9 +31,8 @@ openerp.mail = function(session) { this.params.offset = this.params.offset || 0; this.params.records = this.params.records || null; this.params.char_show_more = this.params.char_show_more || 100; - // tmp - this.map_hash = {'res.users': []}; - /* DataSets */ + this.map_hash = {'res.users': {'login': [] }}; + /* define DataSets */ this.ds = new session.web.DataSet(this, this.params.res_model); this.ds_users = new session.web.DataSet(this, 'res.users'); }, @@ -45,12 +44,10 @@ openerp.mail = function(session) { this.$element.find('button.oe_mail_button_comment').bind('click', function () { self.do_comment(); }); /* delegate links */ self.$element.find('div.oe_mail_thread_display').delegate('a.intlink', 'click', function (event) { - var res_model = event.srcElement.dataset.resModel; - var res_id = event.srcElement.dataset.resId; self.do_action({ type: 'ir.actions.act_window', - res_model: res_model, - res_id: parseInt(res_id), + res_model: event.srcElement.dataset.resModel, + res_id: parseInt(event.srcElement.dataset.resId), views: [[false, 'form']] }); }); @@ -81,32 +78,30 @@ openerp.mail = function(session) { display_comments: function (records) { var self = this; /* WIP: map matched regexp -> records to browse with name */ - _(records).each(function (record) { - //self.check_internal_links(record.body_text); - }); - //console.log(this.map_hash); + //_(records).each(function (record) { + //self.do_check_internal_links(record.body_text); + //}); _(records).each(function (record) { if (record.type == 'email') { record.mini_url = ('/mail/static/src/img/email_icon.png'); } else { record.mini_url = self.thread_get_avatar_mini('res.users', 'avatar_mini', record.user_id[0]); } + // body text manipulation record.body_text = self.do_clean_text(record.body_text); - record.tr_body_text = self.truncate_string(record.body_text, self.params.char_show_more); + record.tr_body_text = self.do_truncate_string(record.body_text, self.params.char_show_more); record.body_text = self.do_replace_internal_links(record.body_text); if (record.tr_body_text) record.tr_body_text = self.do_replace_internal_links(record.tr_body_text); + // render $(session.web.qweb.render('ThreadMsg', {'record': record})).appendTo(self.$element.find('div.oe_mail_thread_display')); + // truncated: hide full-text, show summary, add buttons if (record.tr_body_text) { var node = self.$element.find('span.oe_mail_msg_body:last').append(' [ ... Show less]'); self.$element.find('p.oe_mail_msg_p:last').append($('' + record.tr_body_text + ' [ ... Show more]')); var new_node = self.$element.find('span.oe_mail_msg_body_short:last'); node.hide(); - node.find('a:last').click(function() { - node.hide(); new_node.show(); return false; - }); - new_node.find('a:last').click(function() { - new_node.hide(); node.show(); return false; - }); + node.find('a:last').click(function() { node.hide(); new_node.show(); return false; }); + new_node.find('a:last').click(function() { new_node.hide(); node.show(); return false; }); } }); // update offset for "More" buttons @@ -115,7 +110,7 @@ openerp.mail = function(session) { display_current_user: function () { $('
').html( - '' + '' ).appendTo(this.$element.find('div.oe_mail_msg_image')); }, @@ -137,50 +132,57 @@ openerp.mail = function(session) { while (regex_res != null) { var login = regex_res[2]; var res_id = 1; - string = string.replace(regex_res[0], '@' + login + ''); + //var user_loaded = this.ds_users.call('search', [[['login', 'in', [login]]]]).then(function (records) { + //console.log(records); + //if (records) string = string.replace(regex_res[0], '@' + login + ''); + //}); + //$.when(user_loaded).then(function() { + //}); regex_res = regex_login.exec(string); } return string; }, - ///* check for internal links, and map them to limitate number of queries -- WIP, probably not useful */ - //check_internal_links: function(string) { - ///* shortcut to user: @login */ - ////var regex_login = new RegExp(/(^|\s)@(\w*[a-zA-Z_.]+\w*\s)/g); - //var regex_login = new RegExp(/(^|\s)@(\w*)/g); - //var regex_res = regex_login.exec(string); - //while (regex_res != null) { - //var login = regex_res[2]; - //this.map_hash['res.users'].push(login); - //regex_res = regex_login.exec(string); - //} - ///* internal links: #res.model,name */ - //var regex_intlink = new RegExp(/(^|\s)#(\w*[a-zA-Z_]+\w*)\.(\w+[a-zA-Z_]+\w*),(\w+)/g); - //regex_res = regex_intlink.exec(string); - //while (regex_res != null) { - //var res_model = regex_res[2] + '.' + regex_res[3]; - //var res_name = regex_res[4]; - //if (! (res_model in this.map_hash)) { this.map_hash[res_model] = []; } - //this.map_hash[res_model].push(res_name); - //regex_res = regex_intlink.exec(string); - //} - //}, - thread_get_avatar_mini: function(model, field, id) { return this.session.prefix + '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + (id || ''); }, - - truncate_string: function(string, max_length) { - var string_len = string.length; // TODO: check for whitespaces ? - if (string_len <= max_length) return false; - var new_string = string.slice(0, max_length); - return new_string; + + do_truncate_string: function(string, max_length) { + if (string.length <= max_length) return false; + else return string.slice(0, max_length); }, do_clean_text: function (string) { var html = $('
').text(string.replace(/\s+/g, ' ')).html().replace(new RegExp('<(/)?b\\s*>', 'gi'), '<$1b>'); return html; }, + + /** + * + * var regex_login = new RegExp(/(^|\s)@(\w*[a-zA-Z_.]+\w*\s)/g); + * var regex_login = new RegExp(/(^|\s)@(\w*)/g); + * var regex_intlink = new RegExp(/(^|\s)#(\w*[a-zA-Z_]+\w*)\.(\w+[a-zA-Z_]+\w*),(\w+)/g); + */ + do_check_internal_links: function(string) { + /* shortcut to user: @login */ + var regex_login = new RegExp(/(^|\s)@(\w*)/g); + var regex_res = regex_login.exec(string); + while (regex_res != null) { + var login = regex_res[2]; + this.map_hash['res.users']['login'].push(login); + regex_res = regex_login.exec(string); + } + /* internal links: #res.model,name */ + var regex_intlink = new RegExp(/(^|\s)#(\w*[a-zA-Z_]+\w*)\.(\w+[a-zA-Z_]+\w*),(\w+)/g); + regex_res = regex_intlink.exec(string); + while (regex_res != null) { + var res_model = regex_res[2] + '.' + regex_res[3]; + var res_name = regex_res[4]; + if (! (res_model in this.map_hash)) { this.map_hash[res_model]['name'] = []; } + this.map_hash[res_model]['name'].push(res_name); + regex_res = regex_intlink.exec(string); + } + }, }); From 977d3e997a766cd109dfaa10d9bacb8d626ef5b3 Mon Sep 17 00:00:00 2001 From: "Jiten (OpenERP)" Date: Tue, 28 Feb 2012 10:51:14 +0530 Subject: [PATCH 084/691] [IMP] Improved notifications for hr recruitment. bzr revid: jra@tinyerp.com-20120228052114-oadwo3hewlphflho --- addons/hr_recruitment/hr_recruitment.py | 86 ++++++++++++++++++------- 1 file changed, 64 insertions(+), 22 deletions(-) diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index 4398cb72b1d..67ee298322f 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -171,7 +171,6 @@ class hr_applicant(crm.crm_case, osv.osv): 'partner_mobile': fields.char('Mobile', size=32), 'type_id': fields.many2one('hr.recruitment.degree', 'Degree'), 'department_id': fields.many2one('hr.department', 'Department'), - 'state': fields.selection(AVAILABLE_STATES, 'State', size=16, readonly=True), 'survey': fields.related('job_id', 'survey_id', type='many2one', relation='survey', string='Survey'), 'response': fields.integer("Response"), 'reference': fields.char('Refered By', size=128), @@ -181,6 +180,7 @@ class hr_applicant(crm.crm_case, osv.osv): 'day_close': fields.function(_compute_day, string='Days to Close', \ multi='day_close', type="float", store=True), 'color': fields.integer('Color Index'), + 'emp_id': fields.many2one('hr.employee', 'employee'), 'user_email': fields.related('user_id', 'user_email', type='char', string='User Email', readonly=True), } @@ -392,16 +392,50 @@ class hr_applicant(crm.crm_case, osv.osv): return res def _case_open_notification(self, case, context=None): - message = _("The job request '%s' has been set 'in progress'.") % case.name - case.message_append_note('' ,message, need_action_user_id=case.id) + message = _("Changed Status to In Progress.") + case.message_append_note('' ,message, type='notification', need_action_user_id=case.user_id.id) + return True def _case_close_notification(self, case, context=None): - message = _("Applicant '%s' is being hired.") % case.name - case.message_append_note('' ,message, need_action_user_id=case.id) + print "\n ::: case close notification :: hr rec:::" + case[0].message_mark_done(context) + if case[0].emp_id: + message = _("Applicant is being Hired with employee.") + case[0].message_append_note('' ,message, type='notification') + else: + message = _("Applicant is being Hired without employee.") + case[0].message_append_note('' ,message, type='notification') + return True - def _case_reset_notification(self, case, context=None): - message = _("The job request %s has been Reset as 'New'.") % case.name - case.message_append_note('' ,message, need_action_user_id=case.id) + def _case_cancel_notification(self, case, context=None): + case[0].message_mark_done(context=context) + message = _("Applicant Subject '%s' has been Cancelled.") % (case[0].name) + case[0].message_append_note('' ,message, type="notification") + return True + + def _case_pending_notification(self, case, context=None): + message = _("Changed Status to Pending.") + case[0].message_append_note('' ,message, type='notification', need_action_user_id=case[0].user_id.id) + return True + + def _case_reset_notification(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids, context=context): + self.message_append_note(cr, uid, ids, _('System notification'), + _("Changed Status to New."), type='notification', need_action_user_id=obj.user_id.id, context=context) + return True + + def create_notificate(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids, context=context): + self.message_subscribe(cr, uid, ids, [obj.user_id.id], context=context) + self.message_append_note(cr, uid, ids, _('System notification'), + _("Applicant Created."), type='notification', need_action_user_id=obj.user_id.id, context=context) + return True + + + def create(self, cr, uid, vals, context=None): + obj_id = super(hr_applicant, self).create(cr, uid, vals, context=context) + self.create_notificate(cr, uid, [obj_id], context=context) + return obj_id def case_open(self, cr, uid, ids, context=None): """ @@ -413,11 +447,11 @@ class hr_applicant(crm.crm_case, osv.osv): self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S'),}) return res - def case_close(self, cr, uid, ids, *args): - res = super(hr_applicant, self).case_close(cr, uid, ids, *args) + def case_close(self, cr, uid, ids, context=None): + res = super(hr_applicant, self).case_close(cr, uid, ids, context) return res - def case_close_with_emp(self, cr, uid, ids, *args): + def case_close_with_emp(self, cr, uid, ids, context=None): hr_employee = self.pool.get('hr.employee') model_data = self.pool.get('ir.model.data') act_window = self.pool.get('ir.actions.act_window') @@ -433,10 +467,10 @@ class hr_applicant(crm.crm_case, osv.osv): 'address_home_id': address_id, 'department_id': applicant.department_id.id }) - self.case_close(cr, uid, [applicant.id], *args) + self.write(cr, uid, [applicant.id], {'emp_id': emp_id}) + self.case_close(cr, uid, [applicant.id], context) else: raise osv.except_osv(_('Warning!'),_('You must define Applied Job for this applicant.')) - self._case_reset_notification(applicant, context=context) action_model, action_id = model_data.get_object_reference(cr, uid, 'hr', 'open_view_employee_list') dict_act_window = act_window.read(cr, uid, action_id, []) @@ -445,17 +479,25 @@ class hr_applicant(crm.crm_case, osv.osv): dict_act_window['view_mode'] = 'form,tree' return dict_act_window - def case_reset(self, cr, uid, ids, *args): - """Resets case as draft - @param self: The object pointer - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID for security checks, - @param ids: List of case Ids - @param *args: Tuple Value for additional Params + def case_cancel(self, cr, uid, ids, context=None): + """Overrides cancel for crm_case for setting probability """ + res = super(hr_applicant, self).case_cancel(cr, uid, ids, context) + self.write(cr, uid, ids, {'probability' : 0.0}) + return res - res = super(hr_applicant, self).case_reset(cr, uid, ids, *args) + def case_pending(self, cr, uid, ids, context=None): + """Marks case as pending""" + res = super(hr_applicant, self).case_pending(cr, uid, ids, context) + self.write(cr, uid, ids, {'probability' : 0.0}) + return res + + def case_reset(self, cr, uid, ids, context=None): + """Resets case as draft + """ + res = super(hr_applicant, self).case_reset(cr, uid, ids, context) self.write(cr, uid, ids, {'date_open': False, 'date_closed': False}) + self._case_reset_notification(cr, uid, ids, context) return res def set_priority(self, cr, uid, ids, priority, *args): @@ -476,7 +518,7 @@ class hr_applicant(crm.crm_case, osv.osv): def write(self, cr, uid, ids, vals, context=None): if 'stage_id' in vals and vals['stage_id']: stage = self.pool.get('hr.recruitment.stage').browse(cr, uid, vals['stage_id'], context=context) - text = _("Changed Stage to: %s") % stage.name + text = _("Changed Stage to %s") % stage.name self.message_append(cr, uid, ids, text, body_text=text, context=context) return super(hr_applicant,self).write(cr, uid, ids, vals, context=context) From 2022a090a95b2028d83db65aa81a6b0721cffdae Mon Sep 17 00:00:00 2001 From: "Jiten (OpenERP)" Date: Tue, 28 Feb 2012 11:05:30 +0530 Subject: [PATCH 085/691] [REM] Remove print statement from close notification method. bzr revid: jra@tinyerp.com-20120228053530-u71bnf8evc11f54b --- addons/hr_recruitment/hr_recruitment.py | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index 67ee298322f..37987a62b50 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -397,7 +397,6 @@ class hr_applicant(crm.crm_case, osv.osv): return True def _case_close_notification(self, case, context=None): - print "\n ::: case close notification :: hr rec:::" case[0].message_mark_done(context) if case[0].emp_id: message = _("Applicant is being Hired with employee.") From 76950baec78b64d5a33a46ad55eabf19c6d799f3 Mon Sep 17 00:00:00 2001 From: "Bhumi Thakkar (Open ERP)" Date: Tue, 28 Feb 2012 11:20:38 +0530 Subject: [PATCH 086/691] [IMP] When creating a lead notification put,subscribin when create a lead,when close,cancel,lost,won lead at that time need action is removed. bzr revid: bth@tinyerp.com-20120228055038-7rekfl8whlhgf12h --- addons/crm/crm_lead.py | 61 ++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index b08fcdb78eb..9868689dcc5 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -224,6 +224,12 @@ class crm_lead(crm_case, osv.osv): 'color': 0, } + def create(self, cr, uid, vals, context=None): + obj_id = super(crm_lead, self).create(cr, uid, vals, context) + self._case_create_notification(cr, uid, [obj_id], context=context) + return obj_id + + def onchange_partner_address_id(self, cr, uid, ids, add, email=False): """This function returns value of partner email based on Partner Address """ @@ -265,54 +271,64 @@ class crm_lead(crm_case, osv.osv): def stage_find_won(self, cr, uid, section_id): return self.stage_find_percent(cr, uid, 100.0, section_id) + def _case_create_notification(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids, context=context): + self.message_subscribe(cr, uid, ids, [obj.user_id.id], context=context) + self.message_append_note(cr, uid, ids, _('System notification'), + _("Lead %s is Created.") % (obj.name), type='notification', need_action_user_id=obj.user_id.id, context=context) + return True + def _case_open_notification(self, lead, context=None): if lead.state != 'draft' and lead.state != 'pending': return False if lead.type == 'lead': - message = _("The lead %s has been opened and its state is now in progress.") % (lead.name) + message = _("The lead %s has been opened.") % (lead.name) elif lead.type == 'opportunity': - message = _("The opportunity %s has been opened.") % lead.name + message = _("The opportunity %s has been opened.") % lead.name else: - message = _("The case %s has been opened.") % lead.name - lead.message_append_note('' ,message) + message = _("The case %s has been opened.") % lead.name + lead.message_append_note('' ,message, need_action_user_id=lead.user_id.id) def _case_close_notification(self, lead, context=None): + lead[0].message_mark_done(context) if lead[0].type == 'lead': - message = _("The lead %s has been closed.") % lead[0].name + message = _("The lead %s has been closed.") % lead[0].name else: - message = _("The case %s has been closed.") % lead[0].name - + message = _("The case %s has been closed.") % lead[0].name lead[0].message_append_note('' ,message) def _case_mark_lost_notification(self, lead, context=None): - message = _("The opportunity %s has been marked as lost.") % lead.name + lead.message_mark_done(context) + message = _("The opportunity %s has been marked as lost.") % lead.name lead.message_append_note('' ,message) def _case_mark_won_notification(self, lead, context=None): - message = _("The opportunity %s has been been won.") % lead.name + lead.message_mark_done(context) + message = _("The opportunity %s has been been won.") % lead.name lead.message_append_note('' ,message) def _case_cancel_notification(self, lead, context=None): - message = _("The lead %s has been cancelled.") % (lead[0].name) + lead[0].message_mark_done(context) + message = _("The lead %s has been cancelled.") % (lead[0].name) lead[0].message_append_note('' ,message) def _case_pending_notification(self, case, context=None): if case[0].type == 'lead': - message = _("The lead %s is pending.") % (case[0].name,) + message = _("The lead %s is pending.") % (case[0].name,) elif case[0].type == 'opportunity': - message = _("The opportunity %s is pending.") % (case[0].name,) - case[0].message_append_note('' ,message) + message = _("The opportunity %s is pending.") % (case[0].name,) + case[0].message_append_note('' ,message, need_action_user_id=case[0].user_id.id) def _case_escalate_notification(self, case, context=None): - message = _("The lead %s is escalated.") % (case.name,) + message = _("The lead %s is escalated.") % (case.name,) case.message_append_note('' ,message) def _case_phonecall_notification(self, case, action, context=None): - message = _("%s a call for the opportunity %s.") % (action,case.name) + message = _("%s a call for the opportunity %s.") % (action,case.name) case.message_append_note('', message, need_action_user_id=case.user_id.id) def _case_opportunity_meeting_notification(self, case, context=None): - message = _("The opportunity %s is scheduled for meeting.") % (case.name) + message = _("The opportunity %s is scheduled for meeting.") % (case.name) case.message_append_note('', message, need_action_user_id=case.user_id.id) def case_open(self, cr, uid, ids, context=None): @@ -354,7 +370,6 @@ class crm_lead(crm_case, osv.osv): stage_id = self.stage_find_lost(cr, uid, lead.section_id.id or False) if stage_id: self.stage_set(cr, uid, [lead.id], stage_id) - self._case_mark_lost_notification(lead, context=context) return res def case_mark_won(self, cr, uid, ids, context=None): @@ -472,7 +487,7 @@ class crm_lead(crm_case, osv.osv): subject = subject[0] + ", ".join(subject[1:]) details = "\n\n".join(details) - return opportunity.message_append_note(subject, body_text=details, need_action_user_id=opportunity.user_id.id) + return opportunity.message_append_note(subject, body=details, need_action_user_id=opportunity.user_id.id) def _merge_opportunity_history(self, cr, uid, opportunity_id, opportunities, context=None): message = self.pool.get('mail.message') @@ -582,8 +597,8 @@ class crm_lead(crm_case, osv.osv): } def _convert_opportunity_notification(self, cr, uid, lead, context=None): - success_message = _("Lead %s has been converted to an opportunity.") % lead.name - lead.message_append_note(success_message ,success_message) + success_message = _("Lead %s has been converted to an opportunity.") % lead.name + lead.message_append_note(success_message ,success_message, need_action_user_id=lead.user_id.id) return True def convert_opportunity(self, cr, uid, ids, partner_id, user_ids=False, section_id=False, context=None): @@ -878,14 +893,14 @@ class crm_lead(crm_case, osv.osv): # change probability of lead(s) if required by stage if not vals.get('probability') and stage.on_change: vals['probability'] = stage.probability - text = _("Changed Stage to: %s") % stage.name + text = _("Changed Stage to: %s") % stage.name for case in self.browse(cr, uid, ids, context=context): if case.type == 'lead' or context.get('stage_type') == 'lead': - message = _("The stage of lead %s has been changed to %s.") % (case.name, stage.name) + message = _("The stage of lead %s has been changed to %s.") % (case.name, stage.name) case.message_append_note(text, message) elif case.type == 'opportunity': - message = _("The stage of opportunity %s has been changed to %s.") % (case.name, stage.name) + message = _("The stage of opportunity %s has been changed to %s.") % (case.name, stage.name) case.message_append_note(text, message) return super(crm_lead,self).write(cr, uid, ids, vals, context) From cafffbfb467dea692e090b81bd7fb372b782e51f Mon Sep 17 00:00:00 2001 From: "Bhumi Thakkar (Open ERP)" Date: Tue, 28 Feb 2012 11:25:37 +0530 Subject: [PATCH 087/691] [FIX] Remove and tags from notification messages it is not working so removed. bzr revid: bth@tinyerp.com-20120228055537-asmg2uiuuwssgpex --- addons/sale_crm/wizard/crm_make_sale.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/sale_crm/wizard/crm_make_sale.py b/addons/sale_crm/wizard/crm_make_sale.py index de9a6d4cd1f..fe338b0585f 100644 --- a/addons/sale_crm/wizard/crm_make_sale.py +++ b/addons/sale_crm/wizard/crm_make_sale.py @@ -106,7 +106,7 @@ class crm_make_sale(osv.osv_memory): sale_order = sale_obj.browse(cr, uid, new_id, context=context) case_obj.write(cr, uid, [case.id], {'ref': 'sale.order,%s' % new_id}) new_ids.append(new_id) - message = _("Opportunity %s is converted to Quotation.") % (case.name) + message = _("Opportunity %s is converted to Quotation.") % (case.name) case.message_append_note( _("Converted to Sales Quotation(%s).") % (sale_order.name),message,need_action_user_id=sale_order.user_id.id) if make.close: From 6921b39416703c97c5725f857927c28c69eefed4 Mon Sep 17 00:00:00 2001 From: "Jiten (OpenERP)" Date: Tue, 28 Feb 2012 11:33:57 +0530 Subject: [PATCH 088/691] [IMP] Improved message when applicant hired with/without employee. bzr revid: jra@tinyerp.com-20120228060357-3qvhqvo1hzhc3k6s --- addons/hr_recruitment/hr_recruitment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index 37987a62b50..cc63dd99b62 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -399,10 +399,10 @@ class hr_applicant(crm.crm_case, osv.osv): def _case_close_notification(self, case, context=None): case[0].message_mark_done(context) if case[0].emp_id: - message = _("Applicant is being Hired with employee.") + message = _("Applicant is being Hired as an employee.") case[0].message_append_note('' ,message, type='notification') else: - message = _("Applicant is being Hired without employee.") + message = _("Applicant is being Hired.") case[0].message_append_note('' ,message, type='notification') return True From c763083fc4a61425352a1088ff762d8e14bfd7c7 Mon Sep 17 00:00:00 2001 From: "Bhumi Thakkar (Open ERP)" Date: Tue, 28 Feb 2012 13:15:27 +0530 Subject: [PATCH 089/691] [FIX] remove lead and opportuniy name from notification messages,apply bold tag on stages,put quotation name when converted in quotation from opportunity,put need action only in create and open stage. bzr revid: bth@tinyerp.com-20120228074527-j53q7ulkyhb1uxib --- addons/crm/crm_lead.py | 33 ++++++++++++++----------- addons/sale_crm/wizard/crm_make_sale.py | 2 +- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 9868689dcc5..f166897a2cb 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -275,52 +275,57 @@ class crm_lead(crm_case, osv.osv): for obj in self.browse(cr, uid, ids, context=context): self.message_subscribe(cr, uid, ids, [obj.user_id.id], context=context) self.message_append_note(cr, uid, ids, _('System notification'), - _("Lead %s is Created.") % (obj.name), type='notification', need_action_user_id=obj.user_id.id, context=context) + _("Lead is created."), type='notification', need_action_user_id=obj.user_id.id, context=context) return True def _case_open_notification(self, lead, context=None): if lead.state != 'draft' and lead.state != 'pending': return False if lead.type == 'lead': - message = _("The lead %s has been opened.") % (lead.name) + message = _("The lead has been opened.") elif lead.type == 'opportunity': - message = _("The opportunity %s has been opened.") % lead.name + message = _("The opportunity has been opened.") else: - message = _("The case %s has been opened.") % lead.name + message = _("The case has been opened.") lead.message_append_note('' ,message, need_action_user_id=lead.user_id.id) def _case_close_notification(self, lead, context=None): lead[0].message_mark_done(context) if lead[0].type == 'lead': - message = _("The lead %s has been closed.") % lead[0].name + message = _("The lead has been closed.") + elif lead[0].type == 'opportunity': + message = _("The opportunity has been closed.") else: - message = _("The case %s has been closed.") % lead[0].name + message = _("The case has been closed.") lead[0].message_append_note('' ,message) def _case_mark_lost_notification(self, lead, context=None): lead.message_mark_done(context) - message = _("The opportunity %s has been marked as lost.") % lead.name + message = _("The opportunity has been marked as lost.") lead.message_append_note('' ,message) def _case_mark_won_notification(self, lead, context=None): lead.message_mark_done(context) - message = _("The opportunity %s has been been won.") % lead.name + message = _("The opportunity has been won.") lead.message_append_note('' ,message) def _case_cancel_notification(self, lead, context=None): lead[0].message_mark_done(context) - message = _("The lead %s has been cancelled.") % (lead[0].name) + if lead[0].type == 'lead': + message = _("The lead has been cancelled.") + elif lead[0].type == 'opportunity': + message = _("The opportunity has been cancelled.") lead[0].message_append_note('' ,message) def _case_pending_notification(self, case, context=None): if case[0].type == 'lead': - message = _("The lead %s is pending.") % (case[0].name,) + message = _("The lead is pending.") elif case[0].type == 'opportunity': - message = _("The opportunity %s is pending.") % (case[0].name,) - case[0].message_append_note('' ,message, need_action_user_id=case[0].user_id.id) + message = _("The opportunity is pending.") + case[0].message_append_note('' ,message) def _case_escalate_notification(self, case, context=None): - message = _("The lead %s is escalated.") % (case.name,) + message = _("The lead is escalated.") case.message_append_note('' ,message) def _case_phonecall_notification(self, case, action, context=None): @@ -597,7 +602,7 @@ class crm_lead(crm_case, osv.osv): } def _convert_opportunity_notification(self, cr, uid, lead, context=None): - success_message = _("Lead %s has been converted to an opportunity.") % lead.name + success_message = _("Lead is converted to an opportunity.") lead.message_append_note(success_message ,success_message, need_action_user_id=lead.user_id.id) return True diff --git a/addons/sale_crm/wizard/crm_make_sale.py b/addons/sale_crm/wizard/crm_make_sale.py index fe338b0585f..1d898c5cc8d 100644 --- a/addons/sale_crm/wizard/crm_make_sale.py +++ b/addons/sale_crm/wizard/crm_make_sale.py @@ -106,7 +106,7 @@ class crm_make_sale(osv.osv_memory): sale_order = sale_obj.browse(cr, uid, new_id, context=context) case_obj.write(cr, uid, [case.id], {'ref': 'sale.order,%s' % new_id}) new_ids.append(new_id) - message = _("Opportunity %s is converted to Quotation.") % (case.name) + message = _("Opportunity %s is converted to Quotation %s.") % (case.name, sale_order.name) case.message_append_note( _("Converted to Sales Quotation(%s).") % (sale_order.name),message,need_action_user_id=sale_order.user_id.id) if make.close: From 66f55d4e83f3f5464928bb5f347b37b94e7875db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 28 Feb 2012 09:26:06 +0100 Subject: [PATCH 090/691] [IMP] Wall thread view: lessened size of comment box in threads. bzr revid: tde@openerp.com-20120228082606-bfekwwkemxb0b3xn --- addons/mail/static/src/css/mail.css | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 653f71fc040..43c9c54afd0 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -20,6 +20,11 @@ margin-left: 5%; } +.oe_mail_wall_thread_content div.oe_mail_thread_act .oe_mail_action_textarea { + width: 100%; + height: 20px; + padding: 2px; +} /* Thread */ @@ -110,7 +115,7 @@ } .oe_mail_action_textarea { - width: 60%; + width: 80%; height: 50px; padding: 5px; } From a32d9d7b892effd23fa8f99114624aecc0fbb892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 28 Feb 2012 09:51:11 +0100 Subject: [PATCH 091/691] [DOC] Added comments in mail.js bzr revid: tde@openerp.com-20120228085111-13kx0t7l7bxmywmq --- addons/mail/static/src/js/mail.js | 54 +++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 5b83020fdc4..a2d8a1faed1 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -294,13 +294,21 @@ openerp.mail = function(session) { /* WallView widget: a wall of messages */ mail.WallView = session.web.Widget.extend({ - // QWeb template to use when rendering the object template: 'Wall', + /** + * + * @param {Object} parent parent + * @param {Object} [params] + * @param {Number} [params.limit=20] number of messages to show and fetch + * @var {Array} sorted_comments records sorted by res_model and res_id + * records.res_model = {res_ids} + * records.res_model.res_id = [records] + */ init: function (parent, params) { this._super(parent); - this.filter_search = params['filter_search']; - this.search = {} + this.params.limit = params.limit || 20; + this.sorted_comments = {}; /* DataSets */ this.ds_msg = new session.web.DataSet(this, 'mail.message'); this.ds_thread = new session.web.DataSet(this, 'mail.thread'); @@ -324,7 +332,13 @@ openerp.mail = function(session) { stop: function () { this._super.apply(this, arguments); }, - + + /** + * + * @param {Number} view_id id of the search view to load + * @param {??} defaults ?? + * @param {Boolean} hidden ?? + */ load_search_view: function (view_id, defaults, hidden) { this.searchview = new session.web.SearchView(this, this.ds_msg, view_id || false, defaults || {}, hidden || false); return this.searchview.appendTo(this.$element.find('div.oe_mail_wall_search')); @@ -350,12 +364,16 @@ openerp.mail = function(session) { this.proxy('display_comments')); return load_res; }, - + + /** + * + * @param {Array} records records to show in threads + */ display_comments: function (records) { this.$element.find('div.oe_mail_wall_threads').empty(); - sorted_records = this.sort_comments(records); + this.sort_comments(records, this.sorted_comments); var self = this; - _(sorted_records).each(function (rec_models, model) { // each model + _(this.sorted_comments).each(function (rec_models, model) { // each model _(rec_models).each(function (record_id, id) { // each record var template = 'WallThreadContainer'; var render_res = session.web.qweb.render(template, { @@ -371,8 +389,15 @@ openerp.mail = function(session) { }); }, - sort_comments: function (records) { - sorted_comments = {}; + /** + * Add records to sorted_comments array + * @param {Array} records records from mail.message + * @param {Array} sorted_comments already sorted comments that will be updated + * @returns {Array} sorted_comments + * sorted_comments.res_model = {res_ids} + * sorted_comments.res_model.res_id = [records] + */ + sort_comments: function (records, sorted_comments) { _(records).each(function (record) { if (! (record.model in sorted_comments)) { sorted_comments[record.model] = {}; } if (! (record.res_id in sorted_comments[record.model])) { @@ -382,12 +407,21 @@ openerp.mail = function(session) { return sorted_comments; }, + /** + * Create a domain to fetch new comments according to + * comment already present in sorted_comments + * @returns {Array} fetch_domain (OpenERP domain style) + */ + get_fetch_domain: function (sorted_comments) { + + }, + do_comment: function () { var body_text = this.$element.find('textarea').val(); return this.ds_users.call('message_append_note', [[this.session.uid], 'Tweet', body_text, type='comment']).then( this.proxy('fetch_comments')); }, - + thread_get_mini: function(model, field, id) { id = id || ''; var url = this.session.prefix + '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + id; From e291bf11da4540d5eb17824b59a2e85da0d6f3f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 28 Feb 2012 09:56:07 +0100 Subject: [PATCH 092/691] [DOC] Added comments in mailL.js (Wall widget) bzr revid: tde@openerp.com-20120228085607-oty29x74cwxy6zdi --- addons/mail/static/src/js/mail.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index a2d8a1faed1..156f6ff4590 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -297,7 +297,6 @@ openerp.mail = function(session) { template: 'Wall', /** - * * @param {Object} parent parent * @param {Object} [params] * @param {Number} [params.limit=20] number of messages to show and fetch @@ -334,7 +333,7 @@ openerp.mail = function(session) { }, /** - * + * Loads the mail.message search view * @param {Number} view_id id of the search view to load * @param {??} defaults ?? * @param {Boolean} hidden ?? @@ -343,7 +342,15 @@ openerp.mail = function(session) { this.searchview = new session.web.SearchView(this, this.ds_msg, view_id || false, defaults || {}, hidden || false); return this.searchview.appendTo(this.$element.find('div.oe_mail_wall_search')); }, - + + /** + * Aggregate the domains, contexts and groupbys in parameter + * with those from search form, and then calls fetch_comments + * to actually fetch comments + * @param {Array} domains + * @param {Array} contexts + * @param {Array} groupbys + */ do_searchview_search: function(domains, contexts, groupbys) { var self = this; this.rpc('/web/session/eval_domain_and_context', { @@ -357,7 +364,14 @@ openerp.mail = function(session) { self.fetch_comments(self.search['domain'], self.search['context']); }); }, - + + /** + * Fetches Wall comments (mail.thread.get_pushed_messages) + * @param {Array} domains + * @param {Array} contexts + * @param {Array} groupbys + * @param {Number} limit number of messages to fetch + */ fetch_comments: function (domain, context, offset, limit) { var load_res = this.ds_thread.call('get_pushed_messages', [[this.session.uid], limit = (limit || 100), offset = (offset || 0), domain = (domain || null), context = (context || null) ]).then( @@ -366,7 +380,6 @@ openerp.mail = function(session) { }, /** - * * @param {Array} records records to show in threads */ display_comments: function (records) { From 504e476fc05800249b3cd2cccf31b89b9a32410e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 28 Feb 2012 12:07:40 +0100 Subject: [PATCH 093/691] [IMP] Wall widget: removed unused xml; added more button; added more action (displays more discussions); added comments bzr revid: tde@openerp.com-20120228110740-gcbm02ej6bee4rsl --- addons/mail/static/src/js/mail.js | 79 ++++++++++++++++++++++------- addons/mail/static/src/xml/mail.xml | 13 ++--- 2 files changed, 66 insertions(+), 26 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 156f6ff4590..4a3b92cc895 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -53,7 +53,7 @@ openerp.mail = function(session) { }); /* display user, fetch comments */ this.display_current_user(); - if (this.records) return this.display_comments(this.records); + if (this.params.records) return this.display_comments(this.params.records); else return this.init_comments(); }, @@ -306,7 +306,10 @@ openerp.mail = function(session) { */ init: function (parent, params) { this._super(parent); + this.params = params || {}; this.params.limit = params.limit || 20; + this.params.search = {}; + this.params.domain = []; this.sorted_comments = {}; /* DataSets */ this.ds_msg = new session.web.DataSet(this, 'mail.message'); @@ -324,7 +327,7 @@ openerp.mail = function(session) { self.searchview.on_search.add(self.do_searchview_search); }); /* fetch comments */ - var comments_ready = this.fetch_comments(); + var comments_ready = this.init_comments(); return (search_view_ready && comments_ready); }, @@ -358,10 +361,27 @@ openerp.mail = function(session) { contexts: contexts || [], group_by_seq: groupbys || [] }, function (results) { - self.search['context'] = results.context; - self.search['domain'] = results.domain; - self.search['groupby'] = results.group_by; - self.fetch_comments(self.search['domain'], self.search['context']); + self.params.search['context'] = results.context; + self.params.search['domain'] = results.domain; + self.params.search['groupby'] = results.group_by; + self.init_comments(self.params.search['domain'], self.params.search['context']); + }); + }, + + /** + * Initializes Wall and calls fetch_comments + * @param {Array} domains + * @param {Array} contexts + * @param {Array} groupbys + * @param {Number} limit number of messages to fetch + */ + init_comments: function(domain, context, offset, limit) { + var self = this; + this.params.domain = []; + this.sorted_comments = {}; + this.$element.find('div.oe_mail_wall_threads').empty(); + return this.fetch_comments(domain, context, offset, limit).then(function () { + self.$element.find('button.oe_mail_wall_button_more').bind('click', function () { self.do_more(); }); }); }, @@ -383,10 +403,9 @@ openerp.mail = function(session) { * @param {Array} records records to show in threads */ display_comments: function (records) { - this.$element.find('div.oe_mail_wall_threads').empty(); - this.sort_comments(records, this.sorted_comments); + var sorted_comments = this.sort_comments(records, this.sorted_comments); var self = this; - _(this.sorted_comments).each(function (rec_models, model) { // each model + _(sorted_comments).each(function (rec_models, model) { // each model _(rec_models).each(function (record_id, id) { // each record var template = 'WallThreadContainer'; var render_res = session.web.qweb.render(template, { @@ -394,23 +413,24 @@ openerp.mail = function(session) { 'record_id': id, }); $('
').html(render_res).appendTo(self.$element.find('div.oe_mail_wall_threads')); - self.thread_display = new mail.ThreadDisplay(self, + var thread_display = new mail.ThreadDisplay(self, {'res_model': model, 'res_id': parseInt(id), 'uid': self.session.uid, 'records': record_id} ); - self.thread_display.appendTo(self.$element.find('div.oe_mail_wall_thread_content:last')); + thread_display.appendTo(self.$element.find('div.oe_mail_wall_thread_content:last')); }); }); + $.extend(true, this.sorted_comments, sorted_comments); }, /** * Add records to sorted_comments array * @param {Array} records records from mail.message - * @param {Array} sorted_comments already sorted comments that will be updated - * @returns {Array} sorted_comments - * sorted_comments.res_model = {res_ids} - * sorted_comments.res_model.res_id = [records] + * @returns {Object} sorted_comments: dict + * sorted_comments.res_model = {res_ids} + * sorted_comments.res_model.res_id = [records] */ - sort_comments: function (records, sorted_comments) { + sort_comments: function (records) { + sorted_comments = {} _(records).each(function (record) { if (! (record.model in sorted_comments)) { sorted_comments[record.model] = {}; } if (! (record.res_id in sorted_comments[record.model])) { @@ -423,18 +443,41 @@ openerp.mail = function(session) { /** * Create a domain to fetch new comments according to * comment already present in sorted_comments + * @param {Object} sorted_comments (see sort_comments) * @returns {Array} fetch_domain (OpenERP domain style) */ get_fetch_domain: function (sorted_comments) { - + var domain = []; + _(sorted_comments).each(function (rec_models, model) { //each model + var ids = []; + _(rec_models).each(function (record_id, id) { // each record + ids.push(id); + }); + domain.push('|', ['model', '!=', model], ['res_id', 'not in', ids]); + }); + return domain; }, + /** + * Action: Posts a comment + */ do_comment: function () { var body_text = this.$element.find('textarea').val(); return this.ds_users.call('message_append_note', [[this.session.uid], 'Tweet', body_text, type='comment']).then( this.proxy('fetch_comments')); }, - + + /** + * Action: Shows more discussions + */ + do_more: function () { + var domain = this.get_fetch_domain(this.sorted_comments); + return this.fetch_comments(domain); + }, + + /** + * Tools: get avatar mini (TODO: should be moved in some tools ?) + */ thread_get_mini: function(model, field, id) { id = id || ''; var url = this.session.prefix + '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + id; diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index 386197a0fce..b2cc1e8e0c7 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -13,6 +13,11 @@
+
+ +
@@ -25,14 +30,6 @@
- -
- Discussion about document (id: ) -
-
-
-
-
Discussion about document (id: ) From 17d077bb7d9826f581bb7611e2c9a9ce378785df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 28 Feb 2012 12:23:07 +0100 Subject: [PATCH 094/691] [FIX] Fixed bug when posting a comment from the wall (wrong values given through this.proxy, have to check) bzr revid: tde@openerp.com-20120228112307-8mwlrcqx66h07ood --- addons/mail/static/src/js/mail.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 4a3b92cc895..d49b7a0768c 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -464,7 +464,8 @@ openerp.mail = function(session) { do_comment: function () { var body_text = this.$element.find('textarea').val(); return this.ds_users.call('message_append_note', [[this.session.uid], 'Tweet', body_text, type='comment']).then( - this.proxy('fetch_comments')); + //this.proxy('fetch_comments')); + this.init_comments()); }, /** From 3790daaa69cb90806110669b9a378680aafb7063 Mon Sep 17 00:00:00 2001 From: "Jiten (OpenERP)" Date: Tue, 28 Feb 2012 19:05:16 +0530 Subject: [PATCH 095/691] [IMP] Some changes in hr recruitment - Remove page of 'Communication and History', - Remove group of 'Dates' from notebook page, - Moved button of 'Send new email' on top of right side on main page, - Improved messages and notification. bzr revid: jra@tinyerp.com-20120228133516-iw1zjxhb1xjdzgaf --- addons/hr_recruitment/hr_recruitment.py | 13 ++++---- addons/hr_recruitment/hr_recruitment_view.xml | 33 ++----------------- 2 files changed, 10 insertions(+), 36 deletions(-) diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index cc63dd99b62..1637313a28c 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -392,6 +392,7 @@ class hr_applicant(crm.crm_case, osv.osv): return res def _case_open_notification(self, case, context=None): + case.message_mark_done(context) message = _("Changed Status to In Progress.") case.message_append_note('' ,message, type='notification', need_action_user_id=case.user_id.id) return True @@ -399,22 +400,22 @@ class hr_applicant(crm.crm_case, osv.osv): def _case_close_notification(self, case, context=None): case[0].message_mark_done(context) if case[0].emp_id: - message = _("Applicant is being Hired as an employee.") + message = _("Applicant is Hired and employee created.") case[0].message_append_note('' ,message, type='notification') else: - message = _("Applicant is being Hired.") + message = _("Applicant is Hired.") case[0].message_append_note('' ,message, type='notification') return True def _case_cancel_notification(self, case, context=None): case[0].message_mark_done(context=context) - message = _("Applicant Subject '%s' has been Cancelled.") % (case[0].name) + message = _("Applicant is Cancelled.") case[0].message_append_note('' ,message, type="notification") return True def _case_pending_notification(self, case, context=None): message = _("Changed Status to Pending.") - case[0].message_append_note('' ,message, type='notification', need_action_user_id=case[0].user_id.id) + case[0].message_append_note('' ,message, type='notification') return True def _case_reset_notification(self, cr, uid, ids, context=None): @@ -427,7 +428,7 @@ class hr_applicant(crm.crm_case, osv.osv): for obj in self.browse(cr, uid, ids, context=context): self.message_subscribe(cr, uid, ids, [obj.user_id.id], context=context) self.message_append_note(cr, uid, ids, _('System notification'), - _("Applicant Created."), type='notification', need_action_user_id=obj.user_id.id, context=context) + _("Applicant is Created."), type='notification', need_action_user_id=obj.user_id.id, context=context) return True @@ -517,7 +518,7 @@ class hr_applicant(crm.crm_case, osv.osv): def write(self, cr, uid, ids, vals, context=None): if 'stage_id' in vals and vals['stage_id']: stage = self.pool.get('hr.recruitment.stage').browse(cr, uid, vals['stage_id'], context=context) - text = _("Changed Stage to %s") % stage.name + text = _("Changed Stage to %s.") % stage.name self.message_append(cr, uid, ids, text, body_text=text, context=context) return super(hr_applicant,self).write(cr, uid, ids, vals, context=context) diff --git a/addons/hr_recruitment/hr_recruitment_view.xml b/addons/hr_recruitment/hr_recruitment_view.xml index 65954b20323..2faac78af8c 100644 --- a/addons/hr_recruitment/hr_recruitment_view.xml +++ b/addons/hr_recruitment/hr_recruitment_view.xml @@ -79,6 +79,9 @@
@@ -69,9 +68,10 @@
-
- -
+ +
+
+ You have loaded all messages in this thread.
@@ -117,13 +117,5 @@

- - -
- -
-
From 790df40a912f7cb31f7c40bb23658003c9bfd39f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 29 Feb 2012 10:11:09 +0100 Subject: [PATCH 110/691] [FIX] On Wall: fixed more button on Wall. bzr revid: tde@openerp.com-20120229091109-f0fbr2gdcmjagna6 --- addons/mail/static/src/js/mail.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index fb6f4557734..79283f3ffab 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -43,6 +43,7 @@ openerp.mail = function(session) { this._super.apply(this, arguments); /* events */ this.$element.find('button.oe_mail_button_comment').bind('click', function () { self.do_comment(); }); + this.$element.find('button.oe_mail_button_more').bind('click', function () { self.do_more(); }); this.$element.find('div.oe_mail_thread_display').delegate('a.intlink', 'click', function (event) { // lazy implementation: fetch data and try to redirect self.do_action({ @@ -52,6 +53,7 @@ openerp.mail = function(session) { views: [[false, 'form']] }); }); + this.$element.find('div.oe_mail_thread_nomore').hide(); /* display user, fetch comments */ this.display_current_user(); if (this.params.records) return this.display_comments(this.params.records); @@ -66,8 +68,7 @@ openerp.mail = function(session) { var self = this; this.params.offset = 0; this.$element.find('div.oe_mail_thread_display').empty(); - return this.fetch_comments().then(function() { - self.$element.find('button.oe_mail_button_more').bind('click', function () { self.do_more(); }); }); + return this.fetch_comments().then(); }, fetch_comments: function (limit, offset) { From d03350b164df767e769f7c47ff8949e827b81e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 29 Feb 2012 10:57:52 +0100 Subject: [PATCH 111/691] [IMP] Thread Widget: @login finally implemented. Link is lazy: when clicking, it tries to find a record and redirects if found. bzr revid: tde@openerp.com-20120229095752-t57mepak000bu55r --- addons/mail/static/src/js/mail.js | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 79283f3ffab..01dde5615a3 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -31,7 +31,7 @@ openerp.mail = function(session) { this.params.offset = this.params.offset || 0; this.params.records = this.params.records || null; this.params.char_show_more = this.params.char_show_more || 100; - this.map_hash = {'res.users': {'login': [] }}; + this.map_hash = {}; this.params.show_more = true; /* define DataSets */ this.ds = new session.web.DataSet(this, this.params.res_model); @@ -46,11 +46,20 @@ openerp.mail = function(session) { this.$element.find('button.oe_mail_button_more').bind('click', function () { self.do_more(); }); this.$element.find('div.oe_mail_thread_display').delegate('a.intlink', 'click', function (event) { // lazy implementation: fetch data and try to redirect - self.do_action({ - type: 'ir.actions.act_window', - res_model: event.srcElement.dataset.resModel, - res_id: parseInt(event.srcElement.dataset.resId), - views: [[false, 'form']] + if (! event.srcElement.dataset.resModel) return false; + else var res_model = event.srcElement.dataset.resModel; + if (! event.srcElement.dataset.resLogin) return false; + else var res_login = event.srcElement.dataset.resLogin; + var ds = new session.web.DataSet(self, res_model); + var defer = ds.call('search', [[['login', '=', res_login]]]).then(function (records) { + if (records[0]) { + self.do_action({ + type: 'ir.actions.act_window', + res_model: res_model, + res_id: parseInt(records[0]), + views: [[false, 'form']] + }); + } }); }); this.$element.find('div.oe_mail_thread_nomore').hide(); @@ -175,6 +184,7 @@ openerp.mail = function(session) { var regex_res = regex_login.exec(string); while (regex_res != null) { var login = regex_res[2]; + if (! ('res.users' in this.map_hash)) { this.map_hash['res.users']['name'] = []; } this.map_hash['res.users']['login'].push(login); regex_res = regex_login.exec(string); } From 44ca05c1293aec5e91d8d97569ddaaf46d887920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 29 Feb 2012 11:16:17 +0100 Subject: [PATCH 112/691] [CL] Wall: Cleaned a bit mail.xml: removed unused 'dusplay followers' on wall bzr revid: tde@openerp.com-20120229101617-ubru2sqmjznomrwf --- addons/mail/static/src/xml/mail.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index ef795c9f3e3..66a8e5b0835 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -19,13 +19,6 @@
-
-
- -
-
-
-
From 38e6f8c6ee82af01a2fcb3ec01e4c460351cb77c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 29 Feb 2012 11:17:16 +0100 Subject: [PATCH 113/691] [IMP] Wall: added font color similar to general OpenERP font color bzr revid: tde@openerp.com-20120229101716-pdjtjbiv9p4x32lp --- addons/mail/static/src/css/mail.css | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 195e25807c4..6b9b1e5c1c6 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -3,6 +3,7 @@ .oe_mail_wall { overflow: auto; padding: 5px 5px 5px 5px; + color: #4C4C4C; } /* 2 columns view */ From 747134642b1d45998635ed0ac1ed66f6949e9a1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 29 Feb 2012 11:17:58 +0100 Subject: [PATCH 114/691] [IMP] Wall: messages search_view_id is now passed as an argument to the wall, allowing to display the correct search view bzr revid: tde@openerp.com-20120229101758-vse9o4p5lo133bje --- addons/mail/mail_message_view.xml | 4 ++-- addons/mail/static/src/js/mail.js | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/mail/mail_message_view.xml b/addons/mail/mail_message_view.xml index 09174e54f06..759a60cdb89 100644 --- a/addons/mail/mail_message_view.xml +++ b/addons/mail/mail_message_view.xml @@ -229,13 +229,13 @@ (w)All Feeds mail.all_feeds - + My Feeds mail.all_feeds - + diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 01dde5615a3..7d1de6384e6 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -316,6 +316,7 @@ openerp.mail = function(session) { * @param {Object} parent parent * @param {Object} [params] * @param {Number} [params.limit=20] number of messages to show and fetch + * @param {Number} [params.search_view_id=false] search view id for messages * @var {Array} sorted_comments records sorted by res_model and res_id * records.res_model = {res_ids} * records.res_model.res_id = [records] @@ -324,6 +325,7 @@ openerp.mail = function(session) { this._super(parent); this.params = params || {}; this.params.limit = params.limit || 20; + this.params.search_view_id = params.search_view_id || false; this.params.search = {}; this.params.domain = []; this.sorted_comments = {}; @@ -336,9 +338,10 @@ openerp.mail = function(session) { start: function() { var self = this; this._super.apply(this, arguments); + /* events and buttons */ this.$element.find('button.oe_mail_button_comment').bind('click', function () { self.do_comment(); }); /* load mail.message search view */ - var search_view_loaded = this.load_search_view(); + var search_view_loaded = this.load_search_view(this.params.search_view_id, {}, false); var search_view_ready = $.when(search_view_loaded).then(function () { self.searchview.on_search.add(self.do_searchview_search); }); From 4fd9980327c7e80c34ea25bced12313bfa1948d9 Mon Sep 17 00:00:00 2001 From: "Bhumi Thakkar (Open ERP)" Date: Wed, 29 Feb 2012 15:52:49 +0530 Subject: [PATCH 115/691] [IMP] Call notifications methods from crm base. bzr revid: bth@tinyerp.com-20120229102249-xci8gnbic0npnovs --- addons/crm/crm.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/addons/crm/crm.py b/addons/crm/crm.py index 4c603777820..fdcd7a1a52a 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -289,6 +289,7 @@ class crm_base(object): if not case.user_id: data['user_id'] = uid self.write(cr, uid, [case.id], data) + self._case_open_notification(case, context=context) self._action(cr, uid, cases, 'open') return True @@ -301,6 +302,7 @@ class crm_base(object): cases[0].state # to fill the browse record cache self.write(cr, uid, ids, {'state': 'done', 'date_closed': time.strftime('%Y-%m-%d %H:%M:%S'), }) # We use the cache of cases to keep the old case state + self._case_close_notification(cases, context=context) self._action(cr, uid, cases, 'done') return True @@ -312,6 +314,7 @@ class crm_base(object): cases[0].state # to fill the browse record cache self.write(cr, uid, ids, {'state': 'cancel', 'active': True}) # We use the cache of cases to keep the old case state + self._case_cancel_notification(cases, context=context) self._action(cr, uid, cases, 'cancel') return True @@ -322,6 +325,7 @@ class crm_base(object): cases = self.browse(cr, uid, ids) cases[0].state # to fill the browse record cache self.write(cr, uid, ids, {'state': 'pending', 'active': True}) + self._case_pending_notification(cases, context=context) self._action(cr, uid, cases, 'pending') return True From 0688cc33a2b0164892b27f1999c4efe8ba7dabfe Mon Sep 17 00:00:00 2001 From: "Bhumi Thakkar (Open ERP)" Date: Wed, 29 Feb 2012 17:33:55 +0530 Subject: [PATCH 116/691] [FIX] Remove subject from stage change notification. bzr revid: bth@tinyerp.com-20120229120355-4rnh98lsssrd96l7 --- addons/crm/crm_lead.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 18f746880ca..50aa8dfff06 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -905,15 +905,13 @@ class crm_lead(crm_case, osv.osv): # change probability of lead(s) if required by stage if not vals.get('probability') and stage.on_change: vals['probability'] = stage.probability - text = _("Changed Stage to: %s") % stage.name - for case in self.browse(cr, uid, ids, context=context): if case.type == 'lead' or context.get('stage_type') == 'lead': message = _("The stage of lead has been changed to %s.") % (stage.name) - case.message_append_note(text, message) + case.message_append_note('', message) elif case.type == 'opportunity': message = _("The stage of opportunity has been changed to %s.") % (stage.name) - case.message_append_note(text, message) + case.message_append_note('', message) return super(crm_lead,self).write(cr, uid, ids, vals, context) From 273472b095eb4263fc0f2ab9d48d5e8a6f2a4d0f Mon Sep 17 00:00:00 2001 From: "Jiten (OpenERP)" Date: Wed, 29 Feb 2012 17:40:04 +0530 Subject: [PATCH 117/691] [IMP] Improved write method for change stage id. bzr revid: jra@tinyerp.com-20120229121004-5p1otoss3d9i8vzv --- addons/hr_recruitment/hr_recruitment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index 1637313a28c..4988fef8278 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -518,8 +518,8 @@ class hr_applicant(crm.crm_case, osv.osv): def write(self, cr, uid, ids, vals, context=None): if 'stage_id' in vals and vals['stage_id']: stage = self.pool.get('hr.recruitment.stage').browse(cr, uid, vals['stage_id'], context=context) - text = _("Changed Stage to %s.") % stage.name - self.message_append(cr, uid, ids, text, body_text=text, context=context) + self.message_append_note(cr, uid, ids, _('System notification'), + _("Changed Stage to %s.") % stage.name, type='notification') return super(hr_applicant,self).write(cr, uid, ids, vals, context=context) hr_applicant() From 324eb16d3cc983e3169157a07e43b1410516977a Mon Sep 17 00:00:00 2001 From: "Jiten (OpenERP)" Date: Wed, 29 Feb 2012 17:53:05 +0530 Subject: [PATCH 118/691] [FIX] Remove the need action for state 'In Progress' as per paid instruction. bzr revid: jra@tinyerp.com-20120229122305-ixjn05tqddsng4sb --- addons/hr_recruitment/hr_recruitment.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index 4988fef8278..2a6bc0db64c 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -392,9 +392,8 @@ class hr_applicant(crm.crm_case, osv.osv): return res def _case_open_notification(self, case, context=None): - case.message_mark_done(context) message = _("Changed Status to In Progress.") - case.message_append_note('' ,message, type='notification', need_action_user_id=case.user_id.id) + case.message_append_note('' ,message, type='notification') return True def _case_close_notification(self, case, context=None): From 4847f720442c3fa6faefa60398d245c5814eb2c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 29 Feb 2012 15:23:31 +0100 Subject: [PATCH 119/691] [REF] Wall small cleaning of code bzr revid: tde@openerp.com-20120229142331-zr42yxqy8i0xv7js --- addons/mail/static/src/js/mail.js | 10 +++++----- addons/mail/static/src/xml/mail.xml | 3 +++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 7d1de6384e6..b8a82ff0192 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -339,7 +339,9 @@ openerp.mail = function(session) { var self = this; this._super.apply(this, arguments); /* events and buttons */ - this.$element.find('button.oe_mail_button_comment').bind('click', function () { self.do_comment(); }); + this.$element.find('button.oe_mail_button_comment').bind('click', function () { self.do_comment(); }); + this.$element.find('button.oe_mail_wall_button_more').bind('click', function () { self.do_more(); }); + this.$element.find('div.oe_mail_wall_nomore').hide(); /* load mail.message search view */ var search_view_loaded = this.load_search_view(this.params.search_view_id, {}, false); var search_view_ready = $.when(search_view_loaded).then(function () { @@ -357,7 +359,7 @@ openerp.mail = function(session) { /** * Loads the mail.message search view * @param {Number} view_id id of the search view to load - * @param {??} defaults ?? + * @param {Object} defaults ?? * @param {Boolean} hidden ?? */ load_search_view: function (view_id, defaults, hidden) { @@ -399,9 +401,7 @@ openerp.mail = function(session) { this.params.domain = []; this.sorted_comments = {}; this.$element.find('div.oe_mail_wall_threads').empty(); - return this.fetch_comments(domain, context, offset, limit).then(function () { - self.$element.find('button.oe_mail_wall_button_more').bind('click', function () { self.do_more(); }); - }); + return this.fetch_comments(domain, context, offset, limit); }, /** diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index 66a8e5b0835..1e4e301bc2e 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -17,6 +17,9 @@
+
+ You have loaded all discussions. +
From 5b2b9fb1abe76a0f1b0bb2c0231bca26e5ee218a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 2 Mar 2012 18:07:49 +0100 Subject: [PATCH 120/691] [ADD] Added a thread model in display. Seems working but needs refactoring in the next few days. bzr revid: tde@openerp.com-20120302170749-gaxx90sxy7bi97b3 --- addons/mail/mail_message.py | 1 + addons/mail/mail_message_view.xml | 6 +- addons/mail/mail_thread.py | 45 +++- addons/mail/static/src/css/mail.css | 57 ++--- addons/mail/static/src/js/mail.js | 318 +++++++++++++++++++++------- addons/mail/static/src/xml/mail.xml | 51 ++--- 6 files changed, 326 insertions(+), 152 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index b22b0c792a8..9197c363c1a 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -184,6 +184,7 @@ class mail_message(osv.osv): ('comment', 'Comment'), ('notification', 'System notification'), ], 'Type', help="Message type: e-mail for e-mail message, notification for system message, comment for other messages such as user replies"), + 'parent_id': fields.many2one('mail.message', 'Parent message', help="Parent message if message belongs to a thread"), 'need_action_user_id': fields.many2one('res.users', 'Action by user', help="User requested to perform an action"), } diff --git a/addons/mail/mail_message_view.xml b/addons/mail/mail_message_view.xml index 759a60cdb89..6b131477e46 100644 --- a/addons/mail/mail_message_view.xml +++ b/addons/mail/mail_message_view.xml @@ -13,7 +13,7 @@ - + @@ -30,13 +30,14 @@ - + + @@ -51,6 +52,7 @@ + diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 85c297fb07f..3abe801a1d4 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -97,7 +97,6 @@ class mail_thread(osv.osv): notification_obj = self.pool.get('mail.notification') # notifications do not come from any user, but from system - if vals.get('type') == 'notification': vals['user_id'] = False if not 'need_action_user_id' in vals: vals['need_action_user_id'] = False if not 'model' in vals: vals['model'] = False if not 'res_id' in vals: vals['res_id'] = 0 @@ -118,8 +117,19 @@ class mail_thread(osv.osv): # push to need_action_user_id if user does not follow the object if vals['need_action_user_id'] and not need_action_pushed: notification_obj.create(cr, uid, {'user_id': vals['need_action_user_id'], 'message_id': msg_id}, context=context) + + # parse message to get requested users + user_ids = self.message_parse_users(cr, uid, [msg_id], 'body_text', context=context) + for user_id in user_ids: + notification_obj.create(cr, uid, {'user_id': user_id, 'message_id': msg_id}, context=context) + return msg_id - + + def message_parse_users(self, cr, uid, ids, field_name='body_text', context=None): + '''Parse message content; if find @login: returns the related id''' + user_ids = [] + return user_ids + def message_capable_models(self, cr, uid, context=None): ret_dict = {} for model_name in self.pool.obj_list(): @@ -128,7 +138,7 @@ class mail_thread(osv.osv): ret_dict[model_name] = model._description return ret_dict - def message_append(self, cr, uid, threads, subject, body_text=None, + def message_append(self, cr, uid, threads, subject, parent_id=False, body_text=None, type='email', need_action_user_id=False, email_to=False, email_from=False, email_cc=None, email_bcc=None, reply_to=None, email_date=None, message_id=False, references=None, @@ -270,6 +280,7 @@ class mail_thread(osv.osv): if not 'type' in msg_dict: msg_dict['type'] = 'email' return self.message_append(cr, uid, ids, subject = msg_dict.get('subject'), + parent_id = msg_dict.get('parent_id', False), body_text = msg_dict.get('body_text'), type = msg_dict.get('type'), need_action_user_id = msg_dict.get('need_action_user_id'), @@ -290,23 +301,23 @@ class mail_thread(osv.osv): context = context) # Message loading - def message_load_ids(self, cr, uid, ids, limit=100, offset=0, context=None): + def message_load_ids(self, cr, uid, ids, limit=100, offset=0, domain=[], context=None): """ OpenSocial feature: return thread messages ids (for web compatibility) loading messages: search in mail.messages where res_id = ids, (res_)model = current model """ msg_obj = self.pool.get('mail.message') - msg_ids = msg_obj.search(cr, uid, ['&', ('res_id', 'in', ids), ('model', '=', self._name)], + msg_ids = msg_obj.search(cr, uid, ['&', ('res_id', 'in', ids), ('model', '=', self._name)] + domain, limit=limit, offset=offset, context=context) return msg_ids - def message_load(self, cr, uid, ids, limit=100, offset=0, context=None): + def message_load(self, cr, uid, ids, limit=100, offset=0, domain=[], context=None): """ OpenSocial feature: return thread messages loading messages: search in mail.messages where res_id = ids, (res_)model = current model """ - msg_ids = self.message_load_ids(cr, uid, ids, limit=limit, offset=offset, context=context) + msg_ids = self.message_load_ids(cr, uid, ids, limit=limit, offset=offset, domain=domain, context=context) return self.pool.get('mail.message').read(cr, uid, msg_ids, context=context) - def get_pushed_messages(self, cr, uid, ids, limit=100, offset=0, domain = None, context=None): + def get_pushed_messages(self, cr, uid, ids, limit=100, offset=0, domain=[], context=None): """OpenSocial: wall: get messages to display (=pushed notifications) :param filter_search: TODO :return: list of mail.messages, unsorted @@ -318,9 +329,21 @@ class mail_thread(osv.osv): notifications = notification_obj.browse(cr, uid, notification_ids, context=context) msg_ids = [notification.message_id.id for notification in notifications] # search messages: ids in notifications, add domain coming from wall search view - search_domain = [('id', 'in', msg_ids)] if domain == None else [('id', 'in', msg_ids)] + domain + search_domain = [('id', 'in', msg_ids)] + domain msg_ids = message_obj.search(cr, uid, search_domain, limit=limit, offset=offset, context=context) msgs = message_obj.read(cr, uid, msg_ids, context=context) + # fetch parent message to always have a correctly formated thread + msgs_tmp = msgs[:] + cur_iter = 0; max_iter = 10; modif = True + while (modif and cur_iter <= max_iter): + cur_iter += 1; modif = False + msg_ids_tmp = [] + new_msg_ids = [msg['parent_id'][0] for msg in msgs_tmp if msg['parent_id'] != False and msg['parent_id'][0] not in msg_ids] + msg_ids += new_msg_ids + msgs_tmp = message_obj.read(cr, uid, new_msg_ids, context=context) + msgs += msgs_tmp + # sort by id + msgs.sort(lambda a, b: b['id'].__cmp__(a['id'])) return msgs #------------------------------------------------------ @@ -570,8 +593,8 @@ class mail_thread(osv.osv): # Note specific #------------------------------------------------------ - def message_append_note(self, cr, uid, ids, subject, body, type='notification', need_action_user_id=False, context=None): - return self.message_append(cr, uid, ids, subject, body_text=body, type=type, need_action_user_id=need_action_user_id, context=context) + def message_append_note(self, cr, uid, ids, subject, body, parent_id=False, type='notification', need_action_user_id=False, context=None): + return self.message_append(cr, uid, ids, subject, body_text=body, parent_id=False, type=type, need_action_user_id=need_action_user_id, context=context) # old log overrided method: now calls message_append_note def log(self, cr, uid, id, message, secondary=False, context=None): diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 6b9b1e5c1c6..4f0eea033ea 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -1,4 +1,6 @@ -/* Wall */ +/* ------------------------------ */ +/* Wall */ +/* ------------------------------ */ .oe_mail_wall { overflow: auto; @@ -6,6 +8,10 @@ color: #4C4C4C; } +.oe_mail_wall_search { + width: 55%; +} + /* 2 columns view */ .oe_mail_wall_left { float: left; @@ -27,9 +33,11 @@ padding: 2px; } -/* Thread */ +/* ------------------------------ */ +/* RecordThread */ +/* ------------------------------ */ -.oe_mail_thread_main { +.oe_mail_recthread { overflow: auto; padding: 5px 5px 5px 5px; } @@ -46,15 +54,15 @@ .oe_mail_followers_action, .oe_mail_followers_display { } -/* Thread: 2 columns view */ -.oe_mail_thread_left { +/* RecordThread: 2 columns view */ +.oe_mail_recthread_left { float: left; - width: 65%; + width: 55%; } -.oe_mail_thread_right { +.oe_mail_recthread_right { float: right; - width: 34%; + width: 35%; } .oe_mail_button_follow, .oe_mail_button_unfollow, .oe_mail_button_followers { @@ -71,32 +79,30 @@ width: 80%; } -.oe_mail_thread_more, .oe_mail_thread_nomore { - margin-left: 20%; - margin-right: 40%; - border: 1px solid #D2D9E7; - background: #E0E0E0; - text-align: center; -} - -/* ThreadDisplay */ +/* ------------------------------ */ +/* ThreadDisplay */ +/* ------------------------------ */ .oe_mail_thread { } -.oe_mail_thread_act { -} - -.oe_mail_thread_display { -} - -.oe_mail_thread_msg, .oe_mail_thread_act { - width: 80%; +.oe_mail_thread_display, .oe_mail_thread_act { white-space: normal; margin-bottom: 5px; border-bottom: 1px solid #D2D9E7; } +.oe_mail_thread_subthread { + padding-left: 25%; +} + +.oe_mail_thread_more { + margin-left: 20%; + margin-right: 40%; + border: 1px solid #D2D9E7; + text-align: center; +} + .notification { background: #E0E0E0; } @@ -116,7 +122,6 @@ } .oe_mail_action_textarea { - width: 80%; height: 50px; padding: 5px; } diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index b8a82ff0192..2e270bd82a0 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -4,13 +4,29 @@ openerp.mail = function(session) { /* Add ThreadDisplay widget to registry */ session.web.form.widgets.add( - 'ThreadDisplay', 'openerp.mail.ThreadDisplay'); + 'Thread', 'openerp.mail.Thread'); session.web.page.readonly.add( - 'ThreadDisplay', 'openerp.mail.ThreadDisplay'); + 'Thread', 'openerp.mail.Thread'); - /* ThreadDisplay widget: display a thread of comments */ - mail.ThreadDisplay = session.web.Widget.extend({ - template: 'ThreadDisplay', + /** + * ThreadDisplay widget: this widget handles the display of a thread of messages. + * Two displays are managed through the [thread_level] parameter that sets + * the level number in the thread: + * 1/ 1-level thread: thread_level = 1 + * - root message + * - - sub message (parent_id = root message) + * - - sub message (parent_id = root message) + * 2/ flat thread: thread_level = 0 + * - root message + * - sub message (parent_id = root message) + * - sub message (parent_id = root message) + * This widget has 2 ways of initialization: + * 1/ give records + * 2/ do not give records: will fetch [limit] messages from + * the database, related to record [res_model]:[res_id]. + */ + mail.Thread = session.web.Widget.extend({ + template: 'Thread', /** * @@ -18,22 +34,31 @@ openerp.mail = function(session) { * @params {Object} [params] * @param {String} [params.res_model] res_model of mail.thread object * @param {Number} [params.res_id] res_id of record + * @param {Number} [params.parent_id=false] parent_id of message * @param {Number} [params.uid] user id - * @param {Number} [params.char_show_more=100] number of character to display before adding a "show more" + * @param {Number} [params.thread_level=0] number of levels in the thread (only 0 or 1 currently) + * @param {Number} [params.msg_more_limit=100] number of character to display before having a "show more" link; + * note that the text will not be truncated if it does not have 110% of + * the parameter (ex: 110 characters needed to be truncated and be displayed + * as a 100-characters message) * @param {Number} [params.limit=10] maximum number of messages to fetch - * @param {Number} [params.offset=0] offset for fetchign messages + * @param {Number} [params.offset=0] offset for fetching messages * @param {Number} [params.records=null] records to show instead of fetching messages */ init: function(parent, params) { this._super(parent); this.params = params; - this.params.limit = this.params.limit || 10; + this.params.parent_id = this.params.parent_id || false; + this.params.thread_level = this.params.thread_level || 0; + this.params.msg_more_limit = this.params.msg_more_limit || 100; + this.params.limit = this.params.limit || 2; this.params.offset = this.params.offset || 0; this.params.records = this.params.records || null; - this.params.char_show_more = this.params.char_show_more || 100; + /* DataSets and internal vars */ + this.parent_stack = []; + this.cur_thread_level = 0; this.map_hash = {}; - this.params.show_more = true; - /* define DataSets */ + this.params.thread_show_more = true; this.ds = new session.web.DataSet(this, this.params.res_model); this.ds_users = new session.web.DataSet(this, 'res.users'); }, @@ -42,27 +67,27 @@ openerp.mail = function(session) { var self = this; this._super.apply(this, arguments); /* events */ + this.$element.find('p.oe_mail_p_nomore').hide(); this.$element.find('button.oe_mail_button_comment').bind('click', function () { self.do_comment(); }); this.$element.find('button.oe_mail_button_more').bind('click', function () { self.do_more(); }); this.$element.find('div.oe_mail_thread_display').delegate('a.intlink', 'click', function (event) { // lazy implementation: fetch data and try to redirect if (! event.srcElement.dataset.resModel) return false; else var res_model = event.srcElement.dataset.resModel; - if (! event.srcElement.dataset.resLogin) return false; - else var res_login = event.srcElement.dataset.resLogin; - var ds = new session.web.DataSet(self, res_model); - var defer = ds.call('search', [[['login', '=', res_login]]]).then(function (records) { - if (records[0]) { - self.do_action({ - type: 'ir.actions.act_window', - res_model: res_model, - res_id: parseInt(records[0]), - views: [[false, 'form']] - }); - } - }); + var res_login = event.srcElement.dataset.resLogin; + var res_id = event.srcElement.dataset.resId; + if ((! res_login) && (! res_id)) return false; + if (! res_id) { + var ds = new session.web.DataSet(self, res_model); + var defer = ds.call('search', [[['login', '=', res_login]]]).then(function (records) { + if (records[0]) { + self.do_action({ type: 'ir.actions.act_window', res_model: res_model, res_id: parseInt(records[0]), views: [[false, 'form']]}); + } + else return false; + }); + } + else self.do_action({ type: 'ir.actions.act_window', res_model: res_model, res_id: parseInt(res_id), views: [[false, 'form']]}); }); - this.$element.find('div.oe_mail_thread_nomore').hide(); /* display user, fetch comments */ this.display_current_user(); if (this.params.records) return this.display_comments(this.params.records); @@ -77,72 +102,164 @@ openerp.mail = function(session) { var self = this; this.params.offset = 0; this.$element.find('div.oe_mail_thread_display').empty(); - return this.fetch_comments().then(); + return this.fetch_comments(this.params.limit, this.params.offset).then(); }, fetch_comments: function (limit, offset) { var self = this; var defer = this.ds.call('message_load', [[this.params.res_id], limit=(limit||this.params.limit), offset=(offset||this.params.offset)]); $.when(defer).then(function (records) { - if (records.length < self.params.limit) self.params.show_more = false; + if (records.length < self.params.limit) self.params.thread_show_more = false; self.display_comments(records); - if (self.params.show_more == true) { - self.$element.find('div.oe_mail_thread_more').show(); - self.$element.find('div.oe_mail_thread_nomore').hide(); } + if (self.params.thread_show_more == true) { + self.$element.find('button.oe_mail_button_more').show(); + self.$element.find('p.oe_mail_p_nomore').hide(); } else { - self.$element.find('div.oe_mail_thread_more').hide(); - self.$element.find('div.oe_mail_thread_nomore').show(); } + self.$element.find('button.oe_mail_button_more').hide(); + self.$element.find('p.oe_mail_p_nomore').show(); } }); return defer; }, display_comments: function (records) { var self = this; + // sort comments + var sorted_comments = this.sort_comments(records); + this.sorted_comments = sorted_comments; + this.bidouille = false; + this.sub_com = []; + console.log('display_comments'); + console.log(sorted_comments); + console.log(records); + //return true; + /* WIP: map matched regexp -> records to browse with name */ //_(records).each(function (record) { //self.do_check_internal_links(record.body_text); //}); - _(records).each(function (record) { - if (record.type == 'email') { record.mini_url = ('/mail/static/src/img/email_icon.png'); } - else { record.mini_url = self.thread_get_avatar_mini('res.users', 'avatar_mini', record.user_id[0]); } + + _(sorted_comments).each(function (record) { + console.log('new iteration'); + var sub_comments = [] - // body text manipulation - record.body_text = self.do_clean_text(record.body_text); - record.tr_body_text = self.do_truncate_string(record.body_text, self.params.char_show_more); - record.body_text = self.do_replace_internal_links(record.body_text); - if (record.tr_body_text) record.tr_body_text = self.do_replace_internal_links(record.tr_body_text); - - // render - $(session.web.qweb.render('ThreadMsg', {'record': record})).appendTo(self.$element.find('div.oe_mail_thread_display')); - - // truncated: hide full-text, show summary, add buttons - if (record.tr_body_text) { - var node = self.$element.find('span.oe_mail_msg_body:last').append(' [ ... Show less]'); - self.$element.find('p.oe_mail_msg_p:last').append($('' + record.tr_body_text + ' [ ... Show more]')); - var new_node = self.$element.find('span.oe_mail_msg_body_short:last'); - node.hide(); - node.find('a:last').click(function() { node.hide(); new_node.show(); return false; }); - new_node.find('a:last').click(function() { new_node.hide(); node.show(); return false; }); + if (record.parent_id == self.params.parent_id && self.params.thread_level > 0) { + if (! self.bidouille) { + self.bidouille = record; + } + else { + self.thread = new mail.Thread(self, {'res_model': self.params.res_model, 'res_id': self.params.res_id, 'uid': self.params.uid, + 'records': self.sub_com, 'thread_level': (self.params.thread_level-1), + 'parent_id': record.id}); + self.$element.find('div.oe_mail_thread_msg:last').append('
'); + self.thread.appendTo(self.$element.find('div.oe_mail_thread_subthread:last')); + self.bidouille = record; + self.sub_com = []; + } + } + + else if (self.params.thread_level > 0) { + self.sub_com.push(record); + return true; + } + + self.display_comment(record); + }); + console.log(self.sub_com); + if (self.sub_com.length > 0) { + self.thread = new mail.Thread(self, {'res_model': self.params.res_model, 'res_id': self.params.res_id, 'uid': self.params.uid, + 'records': self.sub_com, 'thread_level': (self.params.thread_level-1), + 'parent_id': self.bidouille.id}); + self.$element.find('div.oe_mail_thread_msg:last').append('
'); + self.thread.appendTo(self.$element.find('div.oe_mail_thread_subthread:last')); + self.sub_com = []; + } + + console.log('end display'); // update offset for "More" buttons this.params.offset += records.length; }, + + /** + * Display a record + */ + display_comment: function (record) { + if (record.type == 'email') { record.mini_url = ('/mail/static/src/img/email_icon.png'); } + else { record.mini_url = this.thread_get_avatar_mini('res.users', 'avatar_mini', record.user_id[0]); } + // body text manipulation + record.body_text = this.do_clean_text(record.body_text); + record.tr_body_text = this.do_truncate_string(record.body_text, this.params.msg_more_limit); + record.body_text = this.do_replace_internal_links(record.body_text); + if (record.tr_body_text) record.tr_body_text = this.do_replace_internal_links(record.tr_body_text); + // render + $(session.web.qweb.render('ThreadMsg', {'record': record})).appendTo(this.$element.find('div.oe_mail_thread_display')); + // truncated: hide full-text, show summary, add buttons + if (record.tr_body_text) { + var node_body = this.$element.find('span.oe_mail_msg_body:last').append(' [ ... Show less]'); + var node_body_short = this.$element.find('span.oe_mail_msg_body_short:last').append(' [ ... Show more]'); + node_body.hide(); + node_body.find('a:last').click(function() { node_body.hide(); node_body_short.show(); return false; }); + node_body_short.find('a:last').click(function() { node_body_short.hide(); node_body.show(); return false; }); + } + }, + + /** + * Sorts records in an hierarchical way, based on parent_id + * @param {Array} records records from mail.message + * @returns {Object} sorted_comments: dict + * sorted_comments.res_model = {res_ids} + * sorted_comments.res_model.res_id = [records] + */ + sort_comments: function (records) { + //console.log('sort_comments'); + if (this.params.thread_level == 0) return records.slice(0); + + var done = false; + var cur_iter = 0; + var max_iter = 10; + + sorted_comments = []; + + tmp_records = records.slice(0); + + _(records).each(function (record, id) { + if (! record.parent_id) { + sorted_comments.push(record); + } + }); + + records.reverse(); + + _(records).each(function (record, id) { + var index = _.indexOf(_.pluck(sorted_comments, 'id'), record.parent_id[0]); + index = 0; + if (index > -1) { + if (record.parent_id) { + sorted_comments.splice(index+1, 0, record); + } + } + }); + + records.reverse(); + return sorted_comments; + }, display_current_user: function () { - $('
').html( - '' - ).appendTo(this.$element.find('div.oe_mail_msg_image')); + return this.$element.find('div.oe_mail_msg_image').empty().html( + ''); }, do_comment: function () { var body_text = this.$element.find('textarea').val(); - return this.ds.call('message_append_note', [[this.params.res_id], 'Reply comment', body_text, type='comment']).then( - this.proxy('init_comments')); + console.log(body_text + this.params.parent_id); + return true; + //return this.ds.call('message_append_note', [[this.params.res_id], 'Reply comment', body_text, parent_id=this.params.parent_id, type='comment']).then( + //this.proxy('init_comments')); }, do_more: function () { - return this.fetch_comments(this.limit, this.offset); + return this.fetch_comments(this.params.limit, this.params.offset); }, do_replace_internal_links: function (string) { @@ -205,20 +322,20 @@ openerp.mail = function(session) { /* Add ThreadView widget to registry */ session.web.form.widgets.add( - 'ThreadView', 'openerp.mail.ThreadView'); + 'ThreadView', 'openerp.mail.RecordThread'); session.web.page.readonly.add( - 'ThreadView', 'openerp.mail.ThreadView'); + 'ThreadView', 'openerp.mail.RecordThread'); /* ThreadView widget: thread of comments */ - mail.ThreadView = session.web.form.Field.extend({ + mail.RecordThread = session.web.form.Field.extend({ // QWeb template to use when rendering the object - form_template: 'Thread', + form_template: 'RecordThread', init: function() { this.is_sub = 0; this.see_sub = 0; this._super.apply(this, arguments); - this.thread_display = null; + this.thread = null; /* DataSets */ this.ds = new session.web.DataSet(this, this.view.model); this.ds_users = new session.web.DataSet(this, 'res.users'); @@ -252,9 +369,10 @@ openerp.mail = function(session) { /* fetch subscribers */ this.fetch_subscribers(); /* create ThreadDisplay widget and render it */ - this.$element.find('div.oe_mail_thread_left').empty(); - this.thread_display = new mail.ThreadDisplay(this, {'res_model': this.view.model, 'res_id': this.view.datarecord.id, 'uid': this.session.uid}); - this.thread_display.appendTo(this.$element.find('div.oe_mail_thread_left')); + this.$element.find('div.oe_mail_recthread_left').empty(); + if (this.thread) this.thread.stop(); + this.thread = new mail.Thread(this, {'res_model': this.view.model, 'res_id': this.view.datarecord.id, 'uid': this.session.uid}); + this.thread.appendTo(this.$element.find('div.oe_mail_recthread_left')); }, fetch_subscribers: function () { @@ -413,7 +531,7 @@ openerp.mail = function(session) { */ fetch_comments: function (domain, context, offset, limit) { var load_res = this.ds_thread.call('get_pushed_messages', - [[this.session.uid], limit = (limit || 100), offset = (offset || 0), domain = (domain || null), context = (context || null) ]).then( + [[this.session.uid], limit = (limit || 2), offset = (offset || 0), domain = (domain || []), context = (context || null) ]).then( this.proxy('display_comments')); return load_res; }, @@ -422,20 +540,24 @@ openerp.mail = function(session) { * @param {Array} records records to show in threads */ display_comments: function (records) { - var sorted_comments = this.sort_comments(records, this.sorted_comments); + var sorted_comments = this.sort_comments(records); var self = this; - _(sorted_comments).each(function (rec_models, model) { // each model - _(rec_models).each(function (record_id, id) { // each record + _(sorted_comments.model_list).each(function (model_name) { + _(sorted_comments.models[model_name].id_list).each(function (id) { + var records = sorted_comments.models[model_name].ids[id]; + console.log('records to send'); + console.log(records); var template = 'WallThreadContainer'; var render_res = session.web.qweb.render(template, { - 'record_model': model, + 'record_model': model_name, 'record_id': id, }); $('
').html(render_res).appendTo(self.$element.find('div.oe_mail_wall_threads')); - var thread_display = new mail.ThreadDisplay(self, - {'res_model': model, 'res_id': parseInt(id), 'uid': self.session.uid, 'records': record_id} + var thread = new mail.Thread(self, { + 'res_model': model_name, 'res_id': parseInt(id), 'uid': self.session.uid, 'records': records, + 'parent_id': false, 'thread_level': 1} ); - thread_display.appendTo(self.$element.find('div.oe_mail_wall_thread_content:last')); + thread.appendTo(self.$element.find('div.oe_mail_wall_thread_content:last')); }); }); $.extend(true, this.sorted_comments, sorted_comments); @@ -447,16 +569,49 @@ openerp.mail = function(session) { * @returns {Object} sorted_comments: dict * sorted_comments.res_model = {res_ids} * sorted_comments.res_model.res_id = [records] + * sorted = [{'hr_holidays': [{3: 'A'}, {2: 'B'}]}, {'crm': [{3: 'A'}, {2: 'B'}]}] */ sort_comments: function (records) { - sorted_comments = {} + sc = {'model_list': [], 'models': {}} + var cur_iter = 0; var max_iter = 10; var modif = true; + /* step1: get roots */ + while ( modif && (cur_iter++) < max_iter) { + modif = false; + _(records).each(function (record) { + if ($.inArray(record.model, sc['model_list']) == -1) { + sc['model_list'].push(record.model); + sc['models'][record.model] = {'id_list': [], 'id_to_root': {}, 'ids': {}}; + modif = true; + } + var sort_id = (record.parent_id) ? record.parent_id[0]: record.id; + if (record.parent_id == false) { + if (_.indexOf(sc['models'][record.model]['id_list'], sort_id) == -1) { + sc['models'][record.model]['id_list'].push(sort_id); + sc['models'][record.model]['ids'][sort_id] = []; + modif = true; + } + } + else { + var test = sc['models'][record.model]['id_to_root'][sort_id]; + if (_.indexOf(sc['models'][record.model]['id_list'], sort_id) != -1) { + sc['models'][record.model]['id_to_root'][record.id] = sort_id; + modif = true; + } + else if ( test ) { + sc['models'][record.model]['id_to_root'][record.id] = test; + modif = true; + } + } + }); + } + /* step2: add records */ _(records).each(function (record) { - if (! (record.model in sorted_comments)) { sorted_comments[record.model] = {}; } - if (! (record.res_id in sorted_comments[record.model])) { - sorted_comments[record.model][record.res_id] = []; } - sorted_comments[record.model][record.res_id].push(record); + var root_id = sc['models'][record.model]['id_to_root'][record.id]; + if (! root_id) root_id = record.id; + sc['models'][record.model]['ids'][root_id].push(record); }); - return sorted_comments; + console.log(sc); + return sc; }, /** @@ -472,7 +627,8 @@ openerp.mail = function(session) { _(rec_models).each(function (record_id, id) { // each record ids.push(id); }); - domain.push('|', ['model', '!=', model], ['res_id', 'not in', ids]); + //domain.push('|', ['model', '!=', model], ['res_id', 'not in', ids]); + domain.push('|', ['model', '!=', model], '!', ['id', 'child_of', ids]); }); return domain; }, diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index 1e4e301bc2e..3020e9b5580 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -14,11 +14,8 @@
- -
-
- You have loaded all discussions. + +

You have loaded all discussions.

@@ -33,11 +30,11 @@
-
+
OpenSocial
-
+
-
+
@@ -52,22 +49,18 @@
-
+
-
-
+
User_image

-
-
+
- -
-
- You have loaded all messages in this thread. + +

You have loaded all messages in this thread.

@@ -76,31 +69,25 @@
- - - - - - + +
+
- +

- - OpenERP System Notification - - - - - - + + + via OpenERP System Notification + - Need action by wrote on
+

From 15581b5286cb2861395f4475c1aeb826c709052d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 2 Mar 2012 18:35:11 +0100 Subject: [PATCH 121/691] [REF] Small refactoring of Wall. Refactoring still needed. bzr revid: tde@openerp.com-20120302173511-eyky2ibpzdvp0hgq --- addons/mail/static/src/js/mail.js | 47 +++++++++++++++---------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 2e270bd82a0..6f9060c75c7 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -555,7 +555,7 @@ openerp.mail = function(session) { $('
').html(render_res).appendTo(self.$element.find('div.oe_mail_wall_threads')); var thread = new mail.Thread(self, { 'res_model': model_name, 'res_id': parseInt(id), 'uid': self.session.uid, 'records': records, - 'parent_id': false, 'thread_level': 1} + 'parent_id': false, 'thread_level': 2} ); thread.appendTo(self.$element.find('div.oe_mail_wall_thread_content:last')); }); @@ -565,40 +565,41 @@ openerp.mail = function(session) { /** * Add records to sorted_comments array - * @param {Array} records records from mail.message - * @returns {Object} sorted_comments: dict - * sorted_comments.res_model = {res_ids} - * sorted_comments.res_model.res_id = [records] - * sorted = [{'hr_holidays': [{3: 'A'}, {2: 'B'}]}, {'crm': [{3: 'A'}, {2: 'B'}]}] + * @param {Array} records records from mail.message sorted by date desc + * @returns {Object} sc sorted_comments: dict + * sc.model_list = [record.model names] + * sc.models.model = { + * 'id_list': list or root_ids + * 'id_to_anc': {'record_id': [ancestor_ids]}, still sorted by date desc + * 'ids': {'root_id': [records]}, still sorted by date desc + * }, for each model */ sort_comments: function (records) { sc = {'model_list': [], 'models': {}} var cur_iter = 0; var max_iter = 10; var modif = true; /* step1: get roots */ while ( modif && (cur_iter++) < max_iter) { + console.log(cur_iter); modif = false; _(records).each(function (record) { if ($.inArray(record.model, sc['model_list']) == -1) { sc['model_list'].push(record.model); - sc['models'][record.model] = {'id_list': [], 'id_to_root': {}, 'ids': {}}; + sc['models'][record.model] = {'id_list': [], 'id_to_anc': {}, 'ids': {}}; + } + var rmod = sc['models'][record.model]; + if (record.parent_id == false && (_.indexOf(rmod['id_list'], record.id) == -1)) { + rmod['id_list'].push(record.id); + rmod['ids'][record.id] = []; modif = true; - } - var sort_id = (record.parent_id) ? record.parent_id[0]: record.id; - if (record.parent_id == false) { - if (_.indexOf(sc['models'][record.model]['id_list'], sort_id) == -1) { - sc['models'][record.model]['id_list'].push(sort_id); - sc['models'][record.model]['ids'][sort_id] = []; - modif = true; - } - } + } else { - var test = sc['models'][record.model]['id_to_root'][sort_id]; - if (_.indexOf(sc['models'][record.model]['id_list'], sort_id) != -1) { - sc['models'][record.model]['id_to_root'][record.id] = sort_id; + var test = rmod['id_to_anc'][record.parent_id[0]]; + if (_.indexOf(rmod['id_list'], record.parent_id[0]) != -1) { + rmod['id_to_anc'][record.id] = record.parent_id[0]; modif = true; } else if ( test ) { - sc['models'][record.model]['id_to_root'][record.id] = test; + rmod['id_to_anc'][record.id] = test; modif = true; } } @@ -606,7 +607,7 @@ openerp.mail = function(session) { } /* step2: add records */ _(records).each(function (record) { - var root_id = sc['models'][record.model]['id_to_root'][record.id]; + var root_id = sc['models'][record.model]['id_to_anc'][record.id]; if (! root_id) root_id = record.id; sc['models'][record.model]['ids'][root_id].push(record); }); @@ -655,9 +656,7 @@ openerp.mail = function(session) { * Tools: get avatar mini (TODO: should be moved in some tools ?) */ thread_get_mini: function(model, field, id) { - id = id || ''; - var url = this.session.prefix + '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + id; - return url; + return this.session.prefix + '/web/binary/image?session_id=' + this.session.session_id + '&model=' + model + '&field=' + field + '&id=' + (id || ''); }, }); }; From 1a3a7c09882ba1036f5c5b9707e0f1d367df8a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 5 Mar 2012 10:05:21 +0100 Subject: [PATCH 122/691] [FIX] Thread widget: fixed bug when looping in records in form view: followers display was not correctly updated. bzr revid: tde@openerp.com-20120305090521-kgi26xvzuhlsckbz --- addons/mail/static/src/js/mail.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 6f9060c75c7..016de0fff16 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -95,7 +95,7 @@ openerp.mail = function(session) { }, stop: function () { - this._super.apply(this, arguments); + //this._super.apply(this, arguments); }, init_comments: function() { @@ -357,29 +357,30 @@ openerp.mail = function(session) { set_value: function() { var self = this; this._super.apply(this, arguments); + this.see_sub = 0; /* hide follow/unfollow/see followers buttons */ - self.$element.find('button.oe_mail_button_follow').hide(); - self.$element.find('button.oe_mail_button_unfollow').hide(); + this.$element.find('button.oe_mail_button_followers').html('Display followers') + this.$element.find('div.oe_mail_followers_display').hide(); + this.$element.find('button.oe_mail_button_follow').hide(); + this.$element.find('button.oe_mail_button_unfollow').hide(); if (! this.view.datarecord.id) { return; } /* find wich (un)follow buttons to show */ - var call_res = this.ds.call('message_is_subscriber', [[this.view.datarecord.id]]).then(function (records) { + var fetch_fol_done = this.ds.call('message_is_subscriber', [[this.view.datarecord.id]]).then(function (records) { if (records == true) { self.is_sub = 1; self.$element.find('button.oe_mail_button_unfollow').show(); } else { self.is_sub = 0; self.$element.find('button.oe_mail_button_follow').show(); } }); /* fetch subscribers */ - this.fetch_subscribers(); + var fetch_sub_done = this.fetch_subscribers(); /* create ThreadDisplay widget and render it */ this.$element.find('div.oe_mail_recthread_left').empty(); if (this.thread) this.thread.stop(); this.thread = new mail.Thread(this, {'res_model': this.view.model, 'res_id': this.view.datarecord.id, 'uid': this.session.uid}); this.thread.appendTo(this.$element.find('div.oe_mail_recthread_left')); + return fetch_fol_done && fetch_sub_done; }, fetch_subscribers: function () { - var follow_res = this.ds.call('message_get_subscribers', [[this.view.datarecord.id]]).then( - this.proxy('display_subscribers')); - this.$element.find('div.oe_mail_followers_display').hide(); - return follow_res; + return this.ds.call('message_get_subscribers', [[this.view.datarecord.id]]).then(this.proxy('display_subscribers')); }, display_subscribers: function (records) { @@ -394,12 +395,12 @@ openerp.mail = function(session) { do_follow: function () { this.do_toggle_follow(); - return this.ds.call('message_subscribe', [[this.view.datarecord.id]]).then(); + return this.ds.call('message_subscribe', [[this.view.datarecord.id]]).when(); }, do_unfollow: function () { this.do_toggle_follow(); - return this.ds.call('message_unsubscribe', [[this.view.datarecord.id]]).then(); + return this.ds.call('message_unsubscribe', [[this.view.datarecord.id]]).when(); }, do_toggle_follow: function () { From 3529cca4f1fa8aca8131d5d7486c827b9d41a54d Mon Sep 17 00:00:00 2001 From: "Jiten (OpenERP)" Date: Mon, 5 Mar 2012 17:33:41 +0530 Subject: [PATCH 123/691] [IMP] Create social chatter for 'Project Issues'. bzr revid: jra@tinyerp.com-20120305120341-57h2iiytumjtpa9v --- addons/hr_recruitment/hr_recruitment.py | 17 +- addons/project/project.py | 2 + addons/project/project_view.xml | 2 + addons/project_issue/project_issue.py | 242 +++++++++++++------- addons/project_issue/project_issue_view.xml | 66 ++---- 5 files changed, 191 insertions(+), 138 deletions(-) diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index 2a6bc0db64c..18d3f8545ce 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -392,45 +392,44 @@ class hr_applicant(crm.crm_case, osv.osv): return res def _case_open_notification(self, case, context=None): - message = _("Changed Status to In Progress.") + message = _("Changed Status to in Progress.") case.message_append_note('' ,message, type='notification') return True def _case_close_notification(self, case, context=None): case[0].message_mark_done(context) if case[0].emp_id: - message = _("Applicant is Hired and employee created.") + message = _("Applicant is hired and employee created.") case[0].message_append_note('' ,message, type='notification') else: - message = _("Applicant is Hired.") + message = _("Applicant is hired.") case[0].message_append_note('' ,message, type='notification') return True def _case_cancel_notification(self, case, context=None): case[0].message_mark_done(context=context) - message = _("Applicant is Cancelled.") + message = _("Applicant is cancelled.") case[0].message_append_note('' ,message, type="notification") return True def _case_pending_notification(self, case, context=None): - message = _("Changed Status to Pending.") + message = _("Changed Status to pending.") case[0].message_append_note('' ,message, type='notification') return True def _case_reset_notification(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids, context=context): self.message_append_note(cr, uid, ids, _('System notification'), - _("Changed Status to New."), type='notification', need_action_user_id=obj.user_id.id, context=context) + _("Changed Status to new."), type='notification', need_action_user_id=obj.user_id.id, context=context) return True def create_notificate(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids, context=context): self.message_subscribe(cr, uid, ids, [obj.user_id.id], context=context) self.message_append_note(cr, uid, ids, _('System notification'), - _("Applicant is Created."), type='notification', need_action_user_id=obj.user_id.id, context=context) + _("Applicant is created."), type='notification', need_action_user_id=obj.user_id.id, context=context) return True - def create(self, cr, uid, vals, context=None): obj_id = super(hr_applicant, self).create(cr, uid, vals, context=context) self.create_notificate(cr, uid, [obj_id], context=context) @@ -518,7 +517,7 @@ class hr_applicant(crm.crm_case, osv.osv): if 'stage_id' in vals and vals['stage_id']: stage = self.pool.get('hr.recruitment.stage').browse(cr, uid, vals['stage_id'], context=context) self.message_append_note(cr, uid, ids, _('System notification'), - _("Changed Stage to %s.") % stage.name, type='notification') + _("Changed stage to %s.") % stage.name, type='notification') return super(hr_applicant,self).write(cr, uid, ids, vals, context=context) hr_applicant() diff --git a/addons/project/project.py b/addons/project/project.py index 9966ad02ee8..b9a3ccd0578 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -53,6 +53,7 @@ class project(osv.osv): _name = "project.project" _description = "Project" _inherits = {'account.analytic.account': "analytic_account_id"} + _inherit = ['mail.thread'] def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False): if user == 1: @@ -457,6 +458,7 @@ class task(osv.osv): _description = "Task" _log_create = True _date_name = "date_start" + _inherit = ['mail.thread'] def _resolve_project_id_from_context(self, cr, uid, context=None): diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index 26abe86fe99..fa5d1539e60 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -97,6 +97,7 @@ + @@ -309,6 +310,7 @@ + diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py index b950bfd0b34..646be577211 100644 --- a/addons/project_issue/project_issue.py +++ b/addons/project_issue/project_issue.py @@ -48,44 +48,6 @@ class project_issue(crm.crm_case, osv.osv): _order = "priority, create_date desc" _inherit = ['mail.thread'] - def write(self, cr, uid, ids, vals, context=None): - #Update last action date everytime the user change the stage, the state or send a new email - logged_fields = ['type_id', 'state', 'message_ids'] - if any([field in vals for field in logged_fields]): - vals['date_action_last'] = time.strftime('%Y-%m-%d %H:%M:%S') - return super(project_issue, self).write(cr, uid, ids, vals, context) - - def case_open(self, cr, uid, ids, *args): - """ - @param self: The object pointer - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID for security checks, - @param ids: List of case's Ids - @param *args: Give Tuple Value - """ - - res = super(project_issue, self).case_open(cr, uid, ids, *args) - self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S'), 'user_id' : uid}) - for (id, name) in self.name_get(cr, uid, ids): - message = _("Issue '%s' has been opened.") % name - self.log(cr, uid, id, message) - return res - - def case_close(self, cr, uid, ids, *args): - """ - @param self: The object pointer - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID for security checks, - @param ids: List of case's Ids - @param *args: Give Tuple Value - """ - - res = super(project_issue, self).case_close(cr, uid, ids, *args) - for (id, name) in self.name_get(cr, uid, ids): - message = _("Issue '%s' has been closed.") % name - self.log(cr, uid, id, message) - return res - def _compute_day(self, cr, uid, ids, fields, args, context=None): """ @param cr: the current row, from the database cursor, @@ -112,7 +74,8 @@ class project_issue(crm.crm_case, osv.osv): ans = date_open - date_create date_until = issue.date_open #Calculating no. of working hours to open the issue - hours = cal_obj.interval_hours_get(cr, uid, issue.project_id.resource_calendar_id.id, + if issue.project_id.resource_calendar_id: + hours = cal_obj.interval_hours_get(cr, uid, issue.project_id.resource_calendar_id.id, date_create, date_open) elif field in ['working_hours_close','day_close']: @@ -121,7 +84,8 @@ class project_issue(crm.crm_case, osv.osv): date_until = issue.date_closed ans = date_close - date_create #Calculating no. of working hours to close the issue - hours = cal_obj.interval_hours_get(cr, uid, issue.project_id.resource_calendar_id.id, + if issue.project_id.resource_calendar_id: + hours = cal_obj.interval_hours_get(cr, uid, issue.project_id.resource_calendar_id.id, date_create, date_close) elif field in ['days_since_creation']: @@ -166,6 +130,25 @@ class project_issue(crm.crm_case, osv.osv): return res + def _hours_get(self, cr, uid, ids, field_names, args, context=None): + task_pool = self.pool.get('project.task') + res = {} + for issue in self.browse(cr, uid, ids, context=context): + progress = 0.0 + if issue.task_id: + progress = task_pool._hours_get(cr, uid, [issue.task_id.id], field_names, args, context=context)[issue.task_id.id]['progress'] + res[issue.id] = {'progress' : progress} + return res + + def _get_project(self, cr, uid, context=None): + user = self.pool.get('res.users').browse(cr, uid, uid, context=context) + if user.context_project_id: + return user.context_project_id.id + return False + + def on_change_project(self, cr, uid, ids, project_id, context=None): + return {} + def _get_issue_task(self, cr, uid, ids, context=None): issues = [] issue_pool = self.pool.get('project.issue') @@ -181,16 +164,6 @@ class project_issue(crm.crm_case, osv.osv): issues += issue_pool.search(cr, uid, [('task_id','=',work.task_id.id)]) return issues - def _hours_get(self, cr, uid, ids, field_names, args, context=None): - task_pool = self.pool.get('project.task') - res = {} - for issue in self.browse(cr, uid, ids, context=context): - progress = 0.0 - if issue.task_id: - progress = task_pool._hours_get(cr, uid, [issue.task_id.id], field_names, args, context=context)[issue.task_id.id]['progress'] - res[issue.id] = {'progress' : progress} - return res - _columns = { 'id': fields.integer('ID', readonly=True), 'name': fields.char('Issue', size=128, required=True), @@ -251,15 +224,6 @@ class project_issue(crm.crm_case, osv.osv): }), } - def _get_project(self, cr, uid, context=None): - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - if user.context_project_id: - return user.context_project_id.id - return False - - def on_change_project(self, cr, uid, ids, project_id, context=None): - return {} - _defaults = { 'active': 1, @@ -319,11 +283,13 @@ class project_issue(crm.crm_case, osv.osv): 'user_id': bug.user_id.id, 'planned_hours': 0.0, }) - vals = { 'task_id': new_task_id, 'state':'pending' } + self._convert_to_task_notification(cr, uid, ids, context) + cases = self.browse(cr, uid, ids) + self._case_pending_notification(cases, context=context) case_obj.write(cr, uid, [bug.id], vals) return { @@ -356,28 +322,39 @@ class project_issue(crm.crm_case, osv.osv): def convert_to_bug(self, cr, uid, ids, context=None): return self._convert(cr, uid, ids, 'bug_categ', context=context) - def next_type(self, cr, uid, ids, *args): - for task in self.browse(cr, uid, ids): - typeid = task.type_id.id - types = map(lambda x:x.id, task.project_id.type_ids or []) - if types: - if not typeid: - self.write(cr, uid, task.id, {'type_id': types[0]}) - elif typeid and typeid in types and types.index(typeid) != len(types)-1 : - index = types.index(typeid) - self.write(cr, uid, task.id, {'type_id': types[index+1]}) - return True - - def prev_type(self, cr, uid, ids, *args): + def prev_type(self, cr, uid, ids, context=None): for task in self.browse(cr, uid, ids): typeid = task.type_id.id types = map(lambda x:x.id, task.project_id and task.project_id.type_ids or []) if types: if typeid and typeid in types: index = types.index(typeid) - self.write(cr, uid, task.id, {'type_id': index and types[index-1] or False}) + self.write(cr, uid, [task.id], {'type_id': index and types[index-1] or False}) return True + def next_type(self, cr, uid, ids, context=None): + for task in self.browse(cr, uid, ids): + typeid = task.type_id.id + types = map(lambda x:x.id, task.project_id.type_ids or []) + if types: + if not typeid: + self.write(cr, uid, [task.id], {'type_id': types[0]}) + elif typeid and typeid in types and types.index(typeid) != len(types)-1 : + index = types.index(typeid) + self.write(cr, uid, [task.id], {'type_id': types[index+1]}) + return True + + def write(self, cr, uid, ids, vals, context=None): + #Update last action date everytime the user change the stage, the state or send a new email + logged_fields = ['type_id', 'state', 'message_ids'] + if any([field in vals for field in logged_fields]): + vals['date_action_last'] = time.strftime('%Y-%m-%d %H:%M:%S') + if 'type_id' in vals and vals['type_id']: + stage = self.pool.get('project.task.type').browse(cr, uid, vals['type_id'], context=context) + self.message_append_note(cr, uid, ids, _('System notification'), + _("Changed stage to %s.") % stage.name, type='notification') + return super(project_issue, self).write(cr, uid, ids, vals, context) + def onchange_task_id(self, cr, uid, ids, task_id, context=None): result = {} if not task_id: @@ -385,13 +362,113 @@ class project_issue(crm.crm_case, osv.osv): task = self.pool.get('project.task').browse(cr, uid, task_id, context=context) return {'value':{'user_id': task.user_id.id,}} - def case_escalate(self, cr, uid, ids, *args): + def _case_open_notification(self, case, context=None): + if case.state: + message = _("Issue is opened.") + case.message_append_note('' ,message, type='notification') + return True + + def _case_close_notification(self, case, context=None): + case[0].message_mark_done(context) + message = _("Issue %s is closed.") + case[0].message_append_note('' ,message, type='notification') + return True + + + def _convert_to_task_notification(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids, context=context): + self.message_append_note(cr, uid, ids, _('System notification'), + _("Issue is converted in to task."), type='notification', context=context) + return True + + def create_notificate(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids, context=context): + self.message_append_note(cr, uid, ids, _('System notification'), + _("Issue is created."), type='notification', need_action_user_id=False, context=context) + return True + + def _case_pending_notification(self, case, context=None): + message = _("Issue is on pending.") + case[0].message_append_note('' ,message, type='notification') + return True + + def _case_escalate_notification(self, case, context=None): + if case[0].project_id.project_escalation_id.user_id.id: + message = _("Issue is escalated from project '%s'.") % (case[0].project_id.name) + case[0].message_append_note('' ,message, type='notification', need_action_user_id=case[0].project_id.project_escalation_id.user_id.id, context=context) + else: + message = _("Issue is escalated.") + case[0].message_append_note('' ,message, type='notification', need_action_user_id=False, context=context) + + return True + + def _case_reset_notification(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids, context=context): + self.message_append_note(cr, uid, ids, _('System notification'), + _("Issue is reset as new."), type='notification', need_action_user_id=obj.user_id.id, context=context) + return True + + def _case_cancel_notification(self, case, context=None): + case[0].message_mark_done(context=context) + message = _("Issue is cancelled.") + case[0].message_append_note('' ,message, type="notification") + return True + + def case_reset(self, cr, uid, ids, context=None): + """Resets case as draft + """ + res = super(project_issue, self).case_reset(cr, uid, ids, context) + self.write(cr, uid, ids, {'date_open': False, 'date_closed': False}) + self._case_reset_notification(cr, uid, ids, context) + return res + + def case_pending(self, cr, uid, ids, context=None): + """Marks case as pending""" + res = super(project_issue, self).case_pending(cr, uid, ids, context) + self.write(cr, uid, ids, context) + return res + + def case_cancel(self, cr, uid, ids, context=None): + """Overrides cancel for crm_case for setting probability + """ + res = super(project_issue, self).case_cancel(cr, uid, ids, context) + self.write(cr, uid, ids, context) + return res + + def create(self, cr, uid, vals, context=None): + obj_id = super(project_issue, self).create(cr, uid, vals, context=context) + self.create_notificate(cr, uid, [obj_id], context=context) + return obj_id + + def case_open(self, cr, uid, ids, context=None): + """ + @param self: The object pointer + @param cr: the current row, from the database cursor, + @param uid: the current user’s ID for security checks, + @param ids: List of case's Ids + """ + + res = super(project_issue, self).case_open(cr, uid, ids, context) + self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S'), 'user_id' : uid}) + return res + + def case_close(self, cr, uid, ids, context=None): + """ + @param self: The object pointer + @param cr: the current row, from the database cursor, + @param uid: the current user’s ID for security checks, + @param ids: List of case's Ids + """ + + res = super(project_issue, self).case_close(cr, uid, ids, context) + return res + + def case_escalate(self, cr, uid, ids, context=None): """Escalates case to top level @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param ids: List of case Ids - @param *args: Tuple Value for additional Params """ cases = self.browse(cr, uid, ids) for case in cases: @@ -405,7 +482,7 @@ class project_issue(crm.crm_case, osv.osv): else: raise osv.except_osv(_('Warning !'), _('You cannot escalate this issue.\nThe relevant Project has not configured the Escalation Project!')) self.write(cr, uid, [case.id], data) - self.message_append(cr, uid, cases, _('Escalate')) + self._case_escalate_notification(cases, context=context) return True def message_new(self, cr, uid, msg, custom_values=None, context=None): @@ -437,7 +514,6 @@ class project_issue(crm.crm_case, osv.osv): return res_id def message_update(self, cr, uid, ids, msg, vals=None, default_act='pending', context=None): - if vals is None: vals = {} @@ -493,11 +569,11 @@ class project(osv.osv): } def _check_escalation(self, cr, uid, ids, context=None): - project_obj = self.browse(cr, uid, ids[0], context=context) - if project_obj.project_escalation_id: - if project_obj.project_escalation_id.id == project_obj.id: - return False - return True + project_obj = self.browse(cr, uid, ids[0], context=context) + if project_obj.project_escalation_id: + if project_obj.project_escalation_id.id == project_obj.id: + return False + return True _constraints = [ (_check_escalation, 'Error! You cannot assign escalation to the same project!', ['project_escalation_id']) diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml index d50501279fd..1d6a560158d 100644 --- a/addons/project_issue/project_issue_view.xml +++ b/addons/project_issue/project_issue_view.xml @@ -54,7 +54,12 @@ - + + + +
+
From da087c47b0c7cea83a78fefb16c9cffb9dace1f1 Mon Sep 17 00:00:00 2001 From: "Bhumi Thakkar (Open ERP)" Date: Tue, 6 Mar 2012 14:48:55 +0530 Subject: [PATCH 129/691] [IMP] notification for crm meeting and crm phonecall. bzr revid: bth@tinyerp.com-20120306091855-b7kx0wxxcu81uw0d --- addons/crm/crm.py | 5 ++++ addons/crm/crm_lead.py | 7 ++++++ addons/crm/crm_meeting.py | 34 +++++++++++++++++++++------ addons/crm/crm_meeting_view.xml | 1 + addons/crm/crm_phonecall.py | 39 ++++++++++++++++++++++++++----- addons/crm/crm_phonecall_view.xml | 1 + 6 files changed, 74 insertions(+), 13 deletions(-) diff --git a/addons/crm/crm.py b/addons/crm/crm.py index fdcd7a1a52a..4f2d2a120d8 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -273,6 +273,9 @@ class crm_base(object): def _case_pending_notification(self, case, context=None): return True + def _case_reset_notification(self, case, context=None): + return True + def _case_escalate_notification(self, case, context=None): return True @@ -336,6 +339,7 @@ class crm_base(object): cases = self.browse(cr, uid, ids) cases[0].state # to fill the browse record cache self.write(cr, uid, ids, {'state': 'draft', 'active': True}) + self._case_reset_notification(cases, context=context) self._action(cr, uid, cases, 'draft') return True @@ -485,6 +489,7 @@ class crm_case(crm_base): cases = self.browse(cr, uid, ids) cases[0].state # to fill the browse record cache self.write(cr, uid, ids, {'state': state, 'active': True}) + self._case_reset_notification(cases, context=context); self._action(cr, uid, cases, state) return True diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 50aa8dfff06..ed9cce87a8e 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -334,6 +334,13 @@ class crm_lead(crm_case, osv.osv): message = _("The lead is escalated.") case.message_append_note('' ,message) + def _case_reset_notification(self, case, context=None): + if case[0].type == 'lead': + message = _("The lead is renewed.") + elif case[0].type == 'opportunity': + message = _("The opportunity is renewed.") + case[0].message_append_note('' ,message, need_action_user_id=case[0].user_id.id) + def _case_phonecall_notification(self, cr, uid, ids, case, phonecall, action, context=None): for obj in phonecall.browse(cr, uid, ids, context=context): if action == "schedule" : diff --git a/addons/crm/crm_meeting.py b/addons/crm/crm_meeting.py index 5ba93d526af..10635d66a6c 100644 --- a/addons/crm/crm_meeting.py +++ b/addons/crm/crm_meeting.py @@ -42,7 +42,7 @@ class crm_meeting(crm_base, osv.osv): _name = 'crm.meeting' _description = "Meeting" _order = "id desc" - _inherit = "calendar.event" + _inherit = ["calendar.event","mail.thread"] _columns = { # From crm.case 'name': fields.char('Summary', size=124, required=True, states={'done': [('readonly', True)]}), @@ -87,15 +87,37 @@ class crm_meeting(crm_base, osv.osv): def _case_opportunity_meeting_notification(self, cr, uid, ids, context=None): lead_obj = self.pool.get('crm.lead') - + phonecall_obj = self.pool.get('crm.phonecall') for obj in self.browse(cr, uid, ids, context=context): if(obj.opportunity_id.id): newid = obj.opportunity_id.id - message = _("scheduled for meeting %s.") % (obj.date) + message = _("scheduled meeting on %s for opportunity.") % (obj.date) for lead in lead_obj.browse(cr, uid, [newid], context=context): lead.message_append_note('', message) + obj.message_append_note('', message, need_action_user_id=lead.user_id.id) + elif(obj.phonecall_id.id): + newid = obj.phonecall_id.id + message = _("scheduled meeting on %s for phonecall.") % (obj.date) + for phonecall in phonecall_obj.browse(cr, uid, [newid], context=context): + phonecall.message_append_note('', message) + obj.message_append_note('', message, need_action_user_id=phonecall.user_id.id) - def case_open(self, cr, uid, ids, *args): + def _case_close_notification(self, meeting, context=None): + meeting[0].message_mark_done(context) + message = _("The meeting is done.") + meeting[0].message_append_note('' ,message) + + def _case_reset_notification(self, meeting, context=None): + message = _("The meeting is unconfirmed.") + meeting[0].message_append_note('' ,message) + + def _case_open_notification(self, meeting, context=None): + if meeting.state != 'draft': + return False + message = _("The meeting has been confirmed.") + meeting.message_append_note('' ,message, need_action_user_id=meeting.user_id.id) + + def case_open(self, cr, uid, ids, context=None): """Confirms meeting @param self: The object pointer @param cr: the current row, from the database cursor, @@ -103,11 +125,9 @@ class crm_meeting(crm_base, osv.osv): @param ids: List of Meeting Ids @param *args: Tuple Value for additional Params """ - res = super(crm_meeting, self).case_open(cr, uid, ids, args) + res = super(crm_meeting, self).case_open(cr, uid, ids, context) for (id, name) in self.name_get(cr, uid, ids): - message = _("The meeting '%s' has been confirmed.") % name id=base_calendar.base_calendar_id2real_id(id) - self.log(cr, uid, id, message) return res crm_meeting() diff --git a/addons/crm/crm_meeting_view.xml b/addons/crm/crm_meeting_view.xml index 527f5814be4..cd0b6240d41 100644 --- a/addons/crm/crm_meeting_view.xml +++ b/addons/crm/crm_meeting_view.xml @@ -216,6 +216,7 @@ + diff --git a/addons/crm/crm_phonecall.py b/addons/crm/crm_phonecall.py index 4063157aed9..d7d52120652 100644 --- a/addons/crm/crm_phonecall.py +++ b/addons/crm/crm_phonecall.py @@ -80,6 +80,7 @@ class crm_phonecall(crm_base, osv.osv): def create(self, cr, uid, vals, context=None): obj_id = super(crm_phonecall, self).create(cr, uid, vals, context=context) + self.open_notification(cr, uid, [obj_id], context) return obj_id def _get_default_state(self, cr, uid, context=None): @@ -94,6 +95,29 @@ class crm_phonecall(crm_base, osv.osv): 'user_id': lambda self,cr,uid,ctx: uid, 'active': 1, } + def _case_cancel_notification(self, phonecall, context=None): + phonecall[0].message_mark_done(context) + message = _("The Phonecall is cancelled.") + phonecall[0].message_append_note( _('System notification'), + message, type='notification', context=context) + + def _case_pending_notification(self, phonecall, context=None): + message = _("The Phonecall is pending.") + phonecall[0].message_append_note('' ,message) + + def done_notification(self, cr, uid, ids, context=None): + for phonecall in self.browse(cr, uid, ids): + phonecall.message_mark_done(context) + message = _("The Phonecall is done.") + self.message_append_note(cr, uid, [phonecall.id], _('System notification'), + message, type='notification', context=context) + + def open_notification(self, cr, uid, ids, context=None): + for phonecall in self.browse(cr, uid, ids): + self.message_subscribe(cr, uid, ids, [phonecall.user_id.id], context=context) + message = _("The Phonecall is open.") + self.message_append_note(cr, uid, [phonecall.id], _('System notification'),message, + type='notification', need_action_user_id=phonecall.user_id.id, context=context) # From crm.case def onchange_partner_address_id(self, cr, uid, ids, add, email=False): @@ -105,7 +129,7 @@ class crm_phonecall(crm_base, osv.osv): res['value']['partner_mobile'] = address.mobile return res - def case_close(self, cr, uid, ids, *args): + def case_close(self, cr, uid, ids, context=None): """Overrides close for crm_case for setting close date """ res = True @@ -115,23 +139,26 @@ class crm_phonecall(crm_base, osv.osv): if phone.duration <=0: duration = datetime.now() - datetime.strptime(phone.date, '%Y-%m-%d %H:%M:%S') data.update({'duration': duration.seconds/float(60)}) - res = super(crm_phonecall, self).case_close(cr, uid, [phone_id], args) + res = super(crm_phonecall, self).case_close(cr, uid, [phone_id], context) self.write(cr, uid, [phone_id], data) + self.done_notification(cr, uid, [phone_id], context); return res - def case_reset(self, cr, uid, ids, *args): + def case_reset(self, cr, uid, ids, context=None): """Resets case as Todo """ - res = super(crm_phonecall, self).case_reset(cr, uid, ids, args) + res = super(crm_phonecall, self).case_reset(cr, uid, ids, context) self.write(cr, uid, ids, {'duration': 0.0, 'state':'open'}) + self.open_notification(cr, uid, ids, context) return res - def case_open(self, cr, uid, ids, *args): + def case_open(self, cr, uid, ids, context=None): """Overrides cancel for crm_case for setting Open Date """ - res = super(crm_phonecall, self).case_open(cr, uid, ids, *args) + res = super(crm_phonecall, self).case_open(cr, uid, ids, context) self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')}) + self.open_notification(cr, uid, ids, context) return res def schedule_another_phonecall(self, cr, uid, ids, schedule_time, call_summary, \ diff --git a/addons/crm/crm_phonecall_view.xml b/addons/crm/crm_phonecall_view.xml index 34ef2612623..6bebccdaf6f 100644 --- a/addons/crm/crm_phonecall_view.xml +++ b/addons/crm/crm_phonecall_view.xml @@ -123,6 +123,7 @@ states="cancel" type="object" icon="gtk-convert" /> + From b0d0b176abae6da2efa6c77e769cf6e05c532815 Mon Sep 17 00:00:00 2001 From: "Bhumi Thakkar (Open ERP)" Date: Tue, 6 Mar 2012 15:53:43 +0530 Subject: [PATCH 130/691] [IMP] on create meeting notification. bzr revid: bth@tinyerp.com-20120306102343-h32fhvuzfpuynjtl --- addons/crm/crm_meeting.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/crm/crm_meeting.py b/addons/crm/crm_meeting.py index 10635d66a6c..0261612c32d 100644 --- a/addons/crm/crm_meeting.py +++ b/addons/crm/crm_meeting.py @@ -101,6 +101,9 @@ class crm_meeting(crm_base, osv.osv): for phonecall in phonecall_obj.browse(cr, uid, [newid], context=context): phonecall.message_append_note('', message) obj.message_append_note('', message, need_action_user_id=phonecall.user_id.id) + else: + message = _("scheduled meeting on %s.") % (obj.date) + obj.message_append_note('', message, need_action_user_id=obj.user_id.id) def _case_close_notification(self, meeting, context=None): meeting[0].message_mark_done(context) From d9dca412cc661d129dd1651b55859c64b02a65b2 Mon Sep 17 00:00:00 2001 From: "Bhumi Thakkar (Open ERP)" Date: Tue, 6 Mar 2012 16:20:17 +0530 Subject: [PATCH 131/691] [FIX] changes in reset functions. bzr revid: bth@tinyerp.com-20120306105017-w2znwg19b713v1cb --- addons/crm/crm.py | 6 +++--- addons/crm/crm_lead.py | 15 ++++++++------- addons/crm/crm_meeting.py | 7 ++++--- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/addons/crm/crm.py b/addons/crm/crm.py index 4f2d2a120d8..b504ae70e10 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -273,7 +273,7 @@ class crm_base(object): def _case_pending_notification(self, case, context=None): return True - def _case_reset_notification(self, case, context=None): + def _case_reset_notification(self, cr, uid, ids, context=None): return True def _case_escalate_notification(self, case, context=None): @@ -339,7 +339,7 @@ class crm_base(object): cases = self.browse(cr, uid, ids) cases[0].state # to fill the browse record cache self.write(cr, uid, ids, {'state': 'draft', 'active': True}) - self._case_reset_notification(cases, context=context) + self._case_reset_notification(cr, uid, ids, context=context) self._action(cr, uid, cases, 'draft') return True @@ -489,7 +489,7 @@ class crm_case(crm_base): cases = self.browse(cr, uid, ids) cases[0].state # to fill the browse record cache self.write(cr, uid, ids, {'state': state, 'active': True}) - self._case_reset_notification(cases, context=context); + self._case_reset_notification(cr, uid, ids, context=context) self._action(cr, uid, cases, state) return True diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index ed9cce87a8e..46c643d6bc4 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -271,6 +271,14 @@ class crm_lead(crm_case, osv.osv): def stage_find_won(self, cr, uid, section_id): return self.stage_find_percent(cr, uid, 100.0, section_id) + def _case_reset_notification(self, cr, uid, ids, context=None): + for lead in self.browse(cr, uid, ids, context=context): + if lead.type == 'lead': + message = _("The lead is renewed.") + elif lead.type == 'opportunity': + message = _("The opportunity is renewed.") + lead.message_append_note('' ,message, need_action_user_id=lead.user_id.id) + def _case_create_notification(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids, context=context): self.message_subscribe(cr, uid, ids, [obj.user_id.id], context=context) @@ -334,13 +342,6 @@ class crm_lead(crm_case, osv.osv): message = _("The lead is escalated.") case.message_append_note('' ,message) - def _case_reset_notification(self, case, context=None): - if case[0].type == 'lead': - message = _("The lead is renewed.") - elif case[0].type == 'opportunity': - message = _("The opportunity is renewed.") - case[0].message_append_note('' ,message, need_action_user_id=case[0].user_id.id) - def _case_phonecall_notification(self, cr, uid, ids, case, phonecall, action, context=None): for obj in phonecall.browse(cr, uid, ids, context=context): if action == "schedule" : diff --git a/addons/crm/crm_meeting.py b/addons/crm/crm_meeting.py index 0261612c32d..22586c7b4fb 100644 --- a/addons/crm/crm_meeting.py +++ b/addons/crm/crm_meeting.py @@ -110,9 +110,10 @@ class crm_meeting(crm_base, osv.osv): message = _("The meeting is done.") meeting[0].message_append_note('' ,message) - def _case_reset_notification(self, meeting, context=None): - message = _("The meeting is unconfirmed.") - meeting[0].message_append_note('' ,message) + def _case_reset_notification(self, cr, uid, ids, context=None): + for meeting in self.browse(cr, uid, ids, context=context): + message = _("The lead is renew.") + meeting.message_append_note('' ,message, need_action_user_id=meeting.user_id.id) def _case_open_notification(self, meeting, context=None): if meeting.state != 'draft': From 821b3a773a0e2537c904ce6e253378401d47d8b4 Mon Sep 17 00:00:00 2001 From: "Bhumi Thakkar (Open ERP)" Date: Tue, 6 Mar 2012 18:58:48 +0530 Subject: [PATCH 132/691] [FIX] minor changes for call reset notification function. bzr revid: bth@tinyerp.com-20120306132848-1jskbzll692kn2bs --- addons/crm/crm.py | 1 - addons/crm/crm_lead.py | 1 + addons/crm/crm_meeting.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/crm/crm.py b/addons/crm/crm.py index b504ae70e10..3aee3ec463a 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -489,7 +489,6 @@ class crm_case(crm_base): cases = self.browse(cr, uid, ids) cases[0].state # to fill the browse record cache self.write(cr, uid, ids, {'state': state, 'active': True}) - self._case_reset_notification(cr, uid, ids, context=context) self._action(cr, uid, cases, state) return True diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 46c643d6bc4..62199f7ad15 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -380,6 +380,7 @@ class crm_lead(crm_case, osv.osv): """ res = super(crm_lead, self).case_reset(cr, uid, ids, context) self.write(cr, uid, ids, {'stage_id': False, 'probability': 0.0}) + self._case_reset_notification(cr, uid, ids, context=context) return res def case_mark_lost(self, cr, uid, ids, context=None): diff --git a/addons/crm/crm_meeting.py b/addons/crm/crm_meeting.py index 22586c7b4fb..47117a82fc1 100644 --- a/addons/crm/crm_meeting.py +++ b/addons/crm/crm_meeting.py @@ -112,7 +112,7 @@ class crm_meeting(crm_base, osv.osv): def _case_reset_notification(self, cr, uid, ids, context=None): for meeting in self.browse(cr, uid, ids, context=context): - message = _("The lead is renew.") + message = _("The meeting is renewed.") meeting.message_append_note('' ,message, need_action_user_id=meeting.user_id.id) def _case_open_notification(self, meeting, context=None): From d83bf2298328ee7e5b509210beab5f434e849107 Mon Sep 17 00:00:00 2001 From: "Bhumi Thakkar (Open ERP)" Date: Tue, 6 Mar 2012 19:08:16 +0530 Subject: [PATCH 133/691] [IMP] notifications in mrp,bom,product. bzr revid: bth@tinyerp.com-20120306133816-59cs058o3oq8arro --- addons/mrp/mrp.py | 97 +++++++++++++++---- addons/mrp/mrp_view.xml | 6 +- addons/mrp_operations/mrp_operations.py | 58 ++++++++++- addons/mrp_operations/mrp_operations_view.xml | 1 + addons/product/product.py | 20 +++- addons/product/product_view.xml | 13 +-- .../stock/wizard/stock_change_product_qty.py | 13 ++- 7 files changed, 174 insertions(+), 34 deletions(-) diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 8a25af01e7b..d2db471421a 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -130,6 +130,7 @@ class mrp_bom(osv.osv): """ _name = 'mrp.bom' _description = 'Bill of Material' + _inherit = ['mail.thread'] def _child_compute(self, cr, uid, ids, name, arg, context=None): """ Gets child bom. @@ -312,7 +313,7 @@ class mrp_bom(osv.osv): phantom = False if bom.type == 'phantom' and not bom.bom_lines: newbom = self._bom_find(cr, uid, bom.product_id.id, bom.product_uom.id, properties) - + if newbom: res = self._bom_explode(cr, uid, self.browse(cr, uid, [newbom])[0], factor*bom.product_qty, properties, addthis=True, level=level+10) result = result + res[0] @@ -358,6 +359,19 @@ class mrp_bom(osv.osv): default.update({'name': bom_data['name'] + ' ' + _('Copy'), 'bom_id':False}) return super(mrp_bom, self).copy_data(cr, uid, id, default, context=context) + def create(self, cr, uid, vals, context=None): + obj_id = super(mrp_bom, self).create(cr, uid, vals, context=context) + self.create_notification(cr, uid, [obj_id], context=context) + return obj_id + + def create_notification(self, cr, uid, ids, context=None): + prod_obj = self.pool.get('product.product') + for obj in self.browse(cr, uid, ids, context=context): + for prod in prod_obj.browse(cr, uid, [obj.product_id], context=context): + self.message_append_note(cr, uid, ids, _('System notification'), + _("Bill of Material is Created for %s product.") % (prod.id.name_template), type='notification', context=context) + return True + mrp_bom() class mrp_bom_revision(osv.osv): @@ -393,6 +407,7 @@ class mrp_production(osv.osv): _name = 'mrp.production' _description = 'Manufacturing Order' _date_name = 'date_planned' + _inherit = ['mail.thread'] def _production_calc(self, cr, uid, ids, prop, unknow_none, context=None): """ Calculates total hours and total no. of cycles for a production order. @@ -497,12 +512,54 @@ class mrp_production(osv.osv): (_check_qty, 'Order quantity cannot be negative or zero!', ['product_qty']), ] + def create(self, cr, uid, vals, context=None): + obj_id = super(mrp_production, self).create(cr, uid, vals, context=context) + self.create_notification(cr, uid, [obj_id], context=context) + return obj_id + def unlink(self, cr, uid, ids, context=None): for production in self.browse(cr, uid, ids, context=context): if production.state not in ('draft', 'cancel'): raise osv.except_osv(_('Invalid action !'), _('Cannot delete a manufacturing order in state \'%s\'') % production.state) return super(mrp_production, self).unlink(cr, uid, ids, context=context) + def create_notification(self, cr, uid, ids, context=None): + for obj in self.browse(cr, uid, ids, context=context): + if obj.user_id.id : + self.message_subscribe(cr, uid, ids, [obj.user_id.id], context=context) + self.message_append_note(cr, uid, ids, _('System notification'), + _("Manufacturing Order is Created."), type='notification', need_action_user_id=obj.user_id.id, context=context) + else : + self.message_append_note(cr, uid, ids, _('System notification'), + _("Manufacturing Order is Created."), type='notification', context=context) + return True + + def cancel_notification(self, cr, uid, ids, context=None): + message = _("Manufacturing order is cancelled.") + self.message_append_note(cr, uid, ids, '', message, context=context) + return True + + def ready_notification(self, cr, uid, ids, context=None): + message = _("Manufacturing order is ready to produce.") + self.message_append_note(cr, uid, ids, '', message, context=context) + return True + + def inproduction_notification(self, cr, uid, ids, context=None): + message = _("Manufacturing order is in production.") + self.message_append_note(cr, uid, ids, '', message, context=context) + return True + + def done_notification(self, cr, uid, ids, context=None): + self.message_mark_done(cr, uid, ids, context) + message = _("Manufacturing order is done.") + self.message_append_note(cr, uid, ids, '', message, context=context) + return True + + def waiting_notification(self, cr, uid, ids, context=None): + message = _("Manufacturing order is waiting for goods.") + self.message_append_note(cr, uid, ids, '', message, context=context) + return True + def copy(self, cr, uid, id, default=None, context=None): if default is None: default = {} @@ -629,9 +686,10 @@ class mrp_production(osv.osv): move_obj.action_cancel(cr, uid, [x.id for x in production.move_created_ids]) move_obj.action_cancel(cr, uid, [x.id for x in production.move_lines]) self.write(cr, uid, ids, {'state': 'cancel'}) + self.cancel_notification(cr, uid, ids, context) return True - def action_ready(self, cr, uid, ids): + def action_ready(self, cr, uid, ids, context=None): """ Changes the production state to Ready and location id of stock move. @return: True """ @@ -643,18 +701,18 @@ class mrp_production(osv.osv): if production.move_prod_id: move_obj.write(cr, uid, [production.move_prod_id.id], {'location_id': production.location_dest_id.id}) - - message = _("Manufacturing order '%s' is ready to produce.") % ( name,) - self.log(cr, uid, production_id, message) + self.ready_notification(cr, uid, [production_id], context) return True - def action_production_end(self, cr, uid, ids): + def action_production_end(self, cr, uid, ids, context=None): """ Changes production state to Finish and writes finished date. @return: True """ for production in self.browse(cr, uid, ids): self._costs_generate(cr, uid, production) - return self.write(cr, uid, ids, {'state': 'done', 'date_finished': time.strftime('%Y-%m-%d %H:%M:%S')}) + self.write(cr, uid, ids, {'state': 'done', 'date_finished': time.strftime('%Y-%m-%d %H:%M:%S')}) + self.done_notification(cr, uid, ids, context) + return True def test_production_done(self, cr, uid, ids): """ Tests whether production is done or not. @@ -670,9 +728,9 @@ class mrp_production(osv.osv): return res def _get_subproduct_factor(self, cr, uid, production_id, move_id=None, context=None): - """ Compute the factor to compute the qty of procucts to produce for the given production_id. By default, - it's always equal to the quantity encoded in the production order or the production wizard, but if the - module mrp_subproduct is installed, then we must use the move_id to identify the product to produce + """ Compute the factor to compute the qty of procucts to produce for the given production_id. By default, + it's always equal to the quantity encoded in the production order or the production wizard, but if the + module mrp_subproduct is installed, then we must use the move_id to identify the product to produce and its quantity. :param production_id: ID of the mrp.order :param move_id: ID of the stock move that needs to be produced. Will be used in mrp_subproduct. @@ -698,7 +756,6 @@ class mrp_production(osv.osv): if (produced_product.scrapped) or (produced_product.product_id.id <> production.product_id.id): continue produced_qty += produced_product.product_qty - if production_mode in ['consume','consume_produce']: consumed_data = {} @@ -733,7 +790,7 @@ class mrp_production(osv.osv): prod_name = scheduled.product_id.name_get()[0][1] raise osv.except_osv(_('Warning!'), _('You are going to consume total %s quantities of "%s".\nBut you can only consume up to total %s quantities.') % (qty, prod_name, qty_avail)) if qty <= 0.0: - # we already have more qtys consumed than we need + # we already have more qtys consumed than we need continue raw_product[0].action_consume(qty, raw_product[0].location_id.id, context=context) @@ -819,11 +876,12 @@ class mrp_production(osv.osv): } ) return amount - def action_in_production(self, cr, uid, ids): + def action_in_production(self, cr, uid, ids, context=None): """ Changes state to In Production and writes starting date. @return: True """ self.write(cr, uid, ids, {'state': 'in_production', 'date_start': time.strftime('%Y-%m-%d %H:%M:%S')}) + self.inproduction_notification(cr, uid, ids, context) return True def test_if_product(self, cr, uid, ids): @@ -890,14 +948,14 @@ class mrp_production(osv.osv): 'state': 'waiting', 'company_id': production.company_id.id, }) - + def _make_production_internal_shipment(self, cr, uid, production, context=None): ir_sequence = self.pool.get('ir.sequence') stock_picking = self.pool.get('stock.picking') routing_loc = None pick_type = 'internal' address_id = False - + # Take routing address as a Shipment Address. # If usage of routing location is a internal, make outgoing shipment otherwise internal shipment if production.bom_id.routing_id and production.bom_id.routing_id.location_id: @@ -926,7 +984,7 @@ class mrp_production(osv.osv): stock_move = self.pool.get('stock.move') source_location_id = production.product_id.product_tmpl_id.property_stock_production.id destination_location_id = production.location_dest_id.id - move_name = _('PROD: %s') + production.name + move_name = _('PROD: %s') + production.name data = { 'name': move_name, 'date': production.date_planned, @@ -983,7 +1041,7 @@ class mrp_production(osv.osv): for production in self.browse(cr, uid, ids, context=context): shipment_id = self._make_production_internal_shipment(cr, uid, production, context=context) produce_move_id = self._make_production_produce_line(cr, uid, production, context=context) - + # Take routing location as a Source Location. source_location_id = production.location_src_id.id if production.bom_id.routing_id and production.bom_id.routing_id.location_id: @@ -994,14 +1052,14 @@ class mrp_production(osv.osv): shipment_move_id = self._make_production_internal_shipment_line(cr, uid, line, shipment_id, consume_move_id,\ destination_location_id=source_location_id, context=context) self._make_production_line_procurement(cr, uid, line, shipment_move_id, context=context) - + wf_service.trg_validate(uid, 'stock.picking', shipment_id, 'button_confirm', cr) production.write({'state':'confirmed'}, context=context) message = _("Manufacturing order '%s' is scheduled for the %s.") % ( production.name, datetime.strptime(production.date_planned,'%Y-%m-%d %H:%M:%S').strftime('%m/%d/%Y'), ) - self.log(cr, uid, production.id, message) + self.waiting_notification(cr, uid, [production.id], context); return shipment_id def force_production(self, cr, uid, ids, *args): @@ -1019,6 +1077,7 @@ class mrp_production_workcenter_line(osv.osv): _name = 'mrp.production.workcenter.line' _description = 'Work Order' _order = 'sequence' + _inherit = ['mail.thread'] _columns = { 'name': fields.char('Work Order', size=64, required=True), diff --git a/addons/mrp/mrp_view.xml b/addons/mrp/mrp_view.xml index 9c3fd6eb335..ad90b7dadae 100644 --- a/addons/mrp/mrp_view.xml +++ b/addons/mrp/mrp_view.xml @@ -410,6 +410,7 @@ + @@ -644,6 +645,7 @@