From c510b34778a93c53de069a31256d1015591d5dc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 9 Aug 2012 16:43:45 +0200 Subject: [PATCH 01/72] [REF] mail: mail has now a mesage_subscriber_ids field, many2many modified field, to avoid doing asynchronous queries to have them. Added temp debug field on mail_group. bzr revid: tde@openerp.com-20120809144345-y03iqvhxv8jxo59v --- addons/mail/__init__.py | 2 +- addons/mail/mail_group_view.xml | 1 + addons/mail/mail_subscription.py | 5 +++-- addons/mail/mail_thread.py | 23 +++++++++++++++++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/addons/mail/__init__.py b/addons/mail/__init__.py index cbd477f55e6..cef9fe126aa 100644 --- a/addons/mail/__init__.py +++ b/addons/mail/__init__.py @@ -21,9 +21,9 @@ import mail_alias import mail_message +import mail_subscription import mail_thread import mail_group -import mail_subscription import ir_needaction import res_users import res_partner diff --git a/addons/mail/mail_group_view.xml b/addons/mail/mail_group_view.xml index 5c81d426d6a..fd40a3ed739 100644 --- a/addons/mail/mail_group_view.xml +++ b/addons/mail/mail_group_view.xml @@ -78,6 +78,7 @@ + diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 7ef74641d77..cf33e64dd79 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -965,7 +965,8 @@ class mail_thread(osv.Model): uid instead """ to_subscribe_uids = [uid] if user_ids is None else user_ids - return self.write(cr, uid, ids, {'message_subscriber_ids': [(4, id) for id in to_subscribe_uids]}, context=context) + write_res = self.write(cr, uid, ids, {'message_subscriber_ids': [(4, id) for id in to_subscribe_uids]}, context=context) + return [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_subscriber_ids] def message_unsubscribe(self, cr, uid, ids, user_ids = None, context=None): """ Unsubscribe the user (or user_ids) from the current document. @@ -974,7 +975,8 @@ class mail_thread(osv.Model): uid instead """ to_unsubscribe_uids = [uid] if user_ids is None else user_ids - return self.write(cr, uid, ids, {'message_subscriber_ids': [(3, id) for id in to_unsubscribe_uids]}, context=context) + write_res = self.write(cr, uid, ids, {'message_subscriber_ids': [(3, id) for id in to_unsubscribe_uids]}, context=context) + return [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_subscriber_ids] #------------------------------------------------------ # Notification API diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index b4b8a6e9797..30d83667165 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -22,25 +22,24 @@ openerp_mail_followers = function(session, mail) { init: function() { this._super.apply(this, arguments); - this.params = this.get_definition_options(); - this.params.see_subscribers = true; - this.params.see_subscribers_options = this.params.see_subscribers_options || false; - this.ds = new session.web.DataSetSearch(this, this.view.model); - this.ds_users = new session.web.DataSetSearch(this, 'res.users'); - + debugger + this.params = {}; + this.params.image = this.node.attrs.image || 'image_small'; + this.params.display_followers = true; + this.params.display_control = this.node.attrs.display_control || false; + this.params.display_actions = this.node.attrs.display_actions || false; + this.ds_model = new session.web.DataSetSearch(this, this.view.model); + this.ds_follow = new session.web.DataSetSearch(this, this.field.relation); }, start: function() { var self = this; - // NB: all the widget should be modified to check the actual_mode property on view, not use // any other method to know if the view is in create mode anymore this.view.on("change:actual_mode", this, this._check_visibility); this._check_visibility(); - - // session.mail.ChatterUtils.bind_events(this); this.$element.find('button.oe_mail_button_followers').click(function () { self.do_toggle_followers(); }); - if (! this.params.see_subscribers_options) { + if (! this.params.display_control) { this.$element.find('button.oe_mail_button_followers').hide(); } this.$element.find('button.oe_mail_button_follow').click(function () { self.do_follow(); }) .mouseover(function () { $(this).html('Follow').removeClass('oe_mail_button_mouseout').addClass('oe_mail_button_mouseover'); }) @@ -60,16 +59,15 @@ openerp_mail_followers = function(session, mail) { }, reinit: function() { - this.params.see_subscribers = true; - this.params.see_subscribers_options = this.params.see_subscribers_options || false; + this.params.display_followers = true; + this.params.display_control = this.node.attrs.display_control || false; + this.params.display_actions = this.node.attrs.display_actions || false; this.$element.find('button.oe_mail_button_followers').html('Hide followers') this.$element.find('button.oe_mail_button_follow').hide(); this.$element.find('button.oe_mail_button_unfollow').hide(); }, set_value: function(value_) { - console.log(value_); - // debugger this.reinit(); if (! this.view.datarecord.id || session.web.BufferedDataSet.virtual_id_regex.test(this.view.datarecord.id)) { @@ -80,7 +78,7 @@ openerp_mail_followers = function(session, mail) { }, fetch_subscribers: function (value_) { - return this.ds_users.call('read', [value_ || this.get_value(), ['name', 'image_small']]).then(this.proxy('display_subscribers')); + return this.ds_follow.call('read', [value_ || this.get_value(), ['name', this.params.image]]).then(this.proxy('display_subscribers')); }, display_subscribers: function (records) { @@ -102,17 +100,12 @@ openerp_mail_followers = function(session, mail) { }, do_follow: function () { - return this.ds.call('message_subscribe', [[this.view.datarecord.id]]).pipe(this.proxy('fetch_subscribers')); + return this.ds_model.call('message_subscribe', [[this.view.datarecord.id]]).pipe(this.proxy('set_value')); }, do_unfollow: function () { var self = this; - return this.ds.call('message_unsubscribe', [[this.view.datarecord.id]]).pipe(function (record) { - // debugger - var new_value = self.view.datarecord.message_subscriber_ids; - // return [new_value.splice(_.indexOf(new_value, self.session.uid, true), 1);] - return [2] - }).pipe(this.proxy('set_value')); + return this.ds_model.call('message_unsubscribe', [[this.view.datarecord.id]]).pipe(this.proxy('set_value')); }, do_toggle_followers: function () { From 98b17f6e96d202997605f3f6964a50121cfc6612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 13 Aug 2012 20:09:41 +0200 Subject: [PATCH 07/72] [IMP] mail_thread: many2many_reference: now overrides the 6 command. bzr revid: tde@openerp.com-20120813180941-n0u1xq0dx2cf8rsf --- addons/mail/mail_thread.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index cf33e64dd79..47f74e0ab29 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -62,14 +62,23 @@ class many2many_reference(fields.many2many): continue if act[0] == 0: idnew = obj.create(cr, user, act[2], context=context) - cr.execute('INSERT INTO '+rel+' ('+id1+','+id2+') VALUES (%s,%s,res_model)', (id, idnew, model._name)) + cr.execute('INSERT INTO '+rel+' ('+id1+','+id2+',res_model) VALUES (%s,%s,%s)', (id, idnew, model._name)) elif act[0] == 3: cr.execute('DELETE FROM "'+rel+'" WHERE '+id1+'=%s AND '+id2+'=%s AND res_model=%s', (id, act[1], model._name)) elif act[0] == 4: # following queries are in the same transaction - so should be relatively safe cr.execute('SELECT 1 FROM '+rel+' WHERE '+id1+'=%s AND '+id2+'=%s AND res_model=%s', (id, act[1], model._name)) if not cr.fetchone(): - cr.execute('INSERT INTO '+rel+' ('+id1+','+id2+',res_model) values (%s,%s,%s)', (id, act[1], model._name)) + cr.execute('INSERT INTO '+rel+' ('+id1+','+id2+',res_model) VALUES (%s,%s,%s)', (id, act[1], model._name)) + elif act[0] == 6: + d1, d2,tables = obj.pool.get('ir.rule').domain_get(cr, user, obj._name, context=context) + if d1: + d1 = ' and ' + ' and '.join(d1) + else: + d1 = '' + cr.execute('DELETE FROM '+rel+' WHERE '+id1+'=%s AND res_model=%s AND '+id2+' IN (SELECT '+rel+'.'+id2+' FROM '+rel+', '+','.join(tables)+' WHERE '+rel+'.'+id1+'=%s AND '+rel+'.'+id2+' = '+obj._table+'.id '+ d1 +')', [id, model._name, id]+d2) + for act_nbr in act[2]: + cr.execute('INSERT INTO '+rel+' ('+id1+','+id2+',res_model) VALUES (%s,%s,%s)', (id, act_nbr, model._name)) else: print act return super(many2many_reference, self).set(cr, model, id, name, values, user, context) From 59d8cb124c28904ef7cd9b75bf314c71e12c2c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 13 Aug 2012 20:33:12 +0200 Subject: [PATCH 08/72] [IMP] mail_thread: do not subscribe followers already subscribed. bzr revid: tde@openerp.com-20120813183312-qpuksy9ku7z5zemx --- addons/mail/mail_thread.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 47f74e0ab29..afe3cf2e381 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -973,7 +973,10 @@ class mail_thread(osv.Model): :param user_ids: a list of user_ids; if not set, subscribe uid instead """ + follower_ids = [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_subscriber_ids] to_subscribe_uids = [uid] if user_ids is None else user_ids + if all(follower_id in follower_ids for follower_id in to_subscribe_uids): + return follower_ids write_res = self.write(cr, uid, ids, {'message_subscriber_ids': [(4, id) for id in to_subscribe_uids]}, context=context) return [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_subscriber_ids] From ff0a280a7ede102c79d0d3ca047429d196993759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 13 Aug 2012 21:10:06 +0200 Subject: [PATCH 09/72] [REF] mail.subscription: renamed to mail.followers. Also renamed files accordingly. Views and menu entries have been updated. Also removed an ununsed read field on mail.notification. bzr revid: tde@openerp.com-20120813191006-jf7vygdyb93k7nxf --- ...mail_subscription.py => mail_followers.py} | 21 +++++------- ...ption_view.xml => mail_followers_view.xml} | 32 ++++++++----------- 2 files changed, 21 insertions(+), 32 deletions(-) rename addons/mail/{mail_subscription.py => mail_followers.py} (82%) rename addons/mail/{mail_subscription_view.xml => mail_followers_view.xml} (64%) diff --git a/addons/mail/mail_subscription.py b/addons/mail/mail_followers.py similarity index 82% rename from addons/mail/mail_subscription.py rename to addons/mail/mail_followers.py index eb6f066a2ef..fcdc78d5f0a 100644 --- a/addons/mail/mail_subscription.py +++ b/addons/mail/mail_followers.py @@ -22,19 +22,21 @@ from osv import osv from osv import fields -class mail_subscription(osv.Model): - """ - mail_subscription holds the data related to the follow mechanism inside OpenERP. +class mail_followers(osv.Model): + """ mail_followers holds the data related to the follow mechanism inside + OpenERP. Users can choose to follow documents (records) of any kind that + inherits from mail.thread. Following documents allow to receive + notifications for new messages. A subscription is characterized by: :param: res_model: model of the followed objects :param: res_id: ID of resource (may be 0 for every objects) :param: user_id: user_id of the follower """ - _name = 'mail.subscription' + _name = 'mail.followers' _rec_name = 'id' _log_access = False _order = 'res_model asc' - _description = 'Mail subscription' + _description = 'Mail Document Followers' _columns = { 'res_model': fields.char('Related Document Model', size=128, required=True, select=1, @@ -46,9 +48,7 @@ class mail_subscription(osv.Model): } class mail_notification(osv.Model): - """ - mail_notification is a relational table modeling messages pushed to users. - :param: read: not used currently + """ mail_notification is a relational table modeling messages pushed to users. """ _name = 'mail.notification' _rec_name = 'id' @@ -60,9 +60,4 @@ class mail_notification(osv.Model): ondelete='cascade', required=True, select=1), 'message_id': fields.many2one('mail.message', string='Message', ondelete='cascade', required=True, select=1), - 'read': fields.boolean('Read', help="Not used currently",), - # TODO: add a timestamp ? or use message date ? - } - _defaults = { - 'read': False, } diff --git a/addons/mail/mail_subscription_view.xml b/addons/mail/mail_followers_view.xml similarity index 64% rename from addons/mail/mail_subscription_view.xml rename to addons/mail/mail_followers_view.xml index c3d79d48308..ebb7104c5b3 100644 --- a/addons/mail/mail_subscription_view.xml +++ b/addons/mail/mail_followers_view.xml @@ -2,17 +2,14 @@ - - - - mail.subscription.tree - mail.subscription + + + mail.followers.tree + mail.followers tree 10 - + @@ -20,17 +17,14 @@ - - + mail.notification.tree mail.notification tree 10 - + @@ -38,9 +32,9 @@ - - Subscriptions - mail.subscription + + Followers + mail.followers form tree,form @@ -52,9 +46,9 @@ tree,form - - --> + + --> Date: Mon, 13 Aug 2012 21:13:46 +0200 Subject: [PATCH 10/72] [REF] mail_thread: refactoring of followers continuing. Updated reference to subscription to followers. Also removed message_read_subscribers and message_is_subscriber, not used anymore. bzr revid: tde@openerp.com-20120813191346-cpn09u4xqiesvpwb --- addons/mail/mail_thread.py | 75 +++++++++++--------------------------- 1 file changed, 21 insertions(+), 54 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index afe3cf2e381..d82158ec3b3 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -38,7 +38,7 @@ class many2many_reference(fields.many2many): def _get_query_and_where_params(self, cr, model, ids, values, where_params): """ Add in where: - - mail_subscription.res_model = 'crm.lead' + - mail_followers.res_model = 'crm.lead' """ query = 'SELECT %(rel)s.%(id2)s, %(rel)s.%(id1)s \ FROM %(rel)s, %(from_c)s \ @@ -104,21 +104,20 @@ class mail_thread(osv.Model): default implementation will work for any model. However it is common to override at least the ``message_new`` and ``message_update`` methods (calling ``super``) to add model-specific behavior at - creation and update of a thread; and ``message_get_subscribers`` - to manage more precisely the social aspect of the thread through - the followers. + creation and update of a thread. + + TODO: UPDATE WITIH SUBTYPE / NEW FOLLOW MECHANISM ''' _name = 'mail.thread' _description = 'Email Thread' def _get_message_ids(self, cr, uid, ids, name, args, context=None): res = {} - for id in ids: - message_ids = self.message_search(cr, uid, [id], context=context) - subscriber_ids = self.message_get_subscribers(cr, uid, [id], context=context) + for thread in self.browse(cr, uid, ids, context=context): + message_ids = self.message_search(cr, uid, [thread.id], context=context) res[id] = { 'message_ids': message_ids, - 'message_summary': "9 %d + %d" % (len(message_ids), len(subscriber_ids)), + 'message_summary': "9 %d + %d" % (len(message_ids), len(thread.message_follower_ids)), } return res @@ -133,8 +132,8 @@ class mail_thread(osv.Model): type='one2many', obj='mail.message', _fields_id = 'res_id', string='Temp messages', multi="_get_message_ids", help="Functional field holding messages related to the current document."), - 'message_subscriber_ids': many2many_reference('res.users', - rel='mail_subscription', id1='res_id', id2='user_id', string="Followers", + 'message_follower_ids': many2many_reference('res.users', + rel='mail_followers', id1='res_id', id2='user_id', string="Followers", help="Followers of the document. The followers have full access to " \ "the document details, as well as the conversation."), 'message_state': fields.boolean('Read', @@ -155,7 +154,7 @@ class mail_thread(osv.Model): #------------------------------------------------------ def create(self, cr, uid, vals, context=None): - """Automatically subscribe the creator """ + """ Automatically subscribe the creator """ thread_id = super(mail_thread, self).create(cr, uid, vals, context=context) if thread_id: self.message_subscribe(cr, uid, [thread_id], [uid], context=context) @@ -163,31 +162,24 @@ class mail_thread(osv.Model): def write(self, cr, uid, ids, vals, context=None): """ Override of write to subscribe the writer, except if he has changed - the subscribers (to avoid unsubscribe-->subscribe). """ + the followers (to avoid unfollow-->follow). """ if isinstance(ids, (int, long)): ids = [ids] write_res = super(mail_thread, self).write(cr, uid, ids, vals, context=context) - if write_res and not vals.get('message_subscriber_ids'): + if write_res and not vals.get('message_follower_ids'): self.message_subscribe(cr, uid, ids, [uid], context=context) return write_res; def unlink(self, cr, uid, ids, context=None): - """Override unlink, to automatically delete - - subscriptions - - messages + """Override unlink, to automatically delete messages that are linked with res_model and res_id, not through a foreign key with a 'cascade' ondelete attribute. Notifications will be deleted with messages """ - subscr_obj = self.pool.get('mail.subscription') msg_obj = self.pool.get('mail.message') - # delete subscriptions - subscr_to_del_ids = subscr_obj.search(cr, uid, [('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) - subscr_obj.unlink(cr, uid, subscr_to_del_ids, context=context) # delete messages and notifications msg_to_del_ids = msg_obj.search(cr, uid, [('model', '=', self._name), ('res_id', 'in', ids)], context=context) msg_obj.unlink(cr, uid, msg_to_del_ids, context=context) - return super(mail_thread, self).unlink(cr, uid, ids, context=context) #------------------------------------------------------ @@ -198,12 +190,11 @@ class mail_thread(osv.Model): """ OpenChatter: wrapper of mail.message create method - creates the mail.message - automatically subscribe the message writer - - push the message to subscribed users + - push the message to followers """ if context is None: context = {} - - message_obj = self.pool.get('mail.message') + notification_obj = self.pool.get('mail.notification') body = vals.get('body_html', '') if vals.get('content_subtype') == 'html' else vals.get('body_text', '') @@ -232,7 +223,6 @@ class mail_thread(osv.Model): return msg_id def message_get_user_ids_to_notify(self, cr, uid, thread_ids, new_msg_vals, context=None): - subscription_obj = self.pool.get('mail.subscription') # get body body = new_msg_vals.get('body_html', '') if new_msg_vals.get('content_subtype') == 'html' else new_msg_vals.get('body_text', '') @@ -939,46 +929,23 @@ class mail_thread(osv.Model): """ Returns the current document followers. Basically this method checks in mail.subscription for entries with matching res_model, res_id. - This method can be overriden to add implicit subscribers, such - as project managers, by adding their user_id to the list of - ids returned by this method. """ - subscr_obj = self.pool.get('mail.subscription') + subscr_obj = self.pool.get('mail.followers') subscr_ids = subscr_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) return [sub['user_id'][0] for sub in subscr_obj.read(cr, uid, subscr_ids, ['user_id'], context=context)] - def message_read_subscribers(self, cr, uid, ids, fields=['id', 'name', 'image_small'], context=None): - """ Returns the current document followers as a read result. Used - mainly for Chatter having only one method to call to have - details about users. - """ - user_ids = self.message_get_subscribers(cr, uid, ids, context=context) - return self.pool.get('res.users').read(cr, uid, user_ids, fields=fields, context=context) - - def message_is_subscriber(self, cr, uid, ids, user_id = None, context=None): - """ Check if uid or user_id (if set) is a subscriber to the current - document. - - :param user_id: if set, check is done on user_id; if not set - check is done on uid - """ - sub_user_id = uid if user_id is None else user_id - if sub_user_id in self.message_get_subscribers(cr, uid, ids, context=context): - return True - return False - def message_subscribe(self, cr, uid, ids, user_ids = None, context=None): """ Subscribe the user (or user_ids) to the current document. :param user_ids: a list of user_ids; if not set, subscribe uid instead """ - follower_ids = [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_subscriber_ids] + follower_ids = [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_follower_ids] to_subscribe_uids = [uid] if user_ids is None else user_ids if all(follower_id in follower_ids for follower_id in to_subscribe_uids): return follower_ids - write_res = self.write(cr, uid, ids, {'message_subscriber_ids': [(4, id) for id in to_subscribe_uids]}, context=context) - return [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_subscriber_ids] + write_res = self.write(cr, uid, ids, {'message_follower_ids': [(4, id) for id in to_subscribe_uids]}, context=context) + return [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_follower_ids] def message_unsubscribe(self, cr, uid, ids, user_ids = None, context=None): """ Unsubscribe the user (or user_ids) from the current document. @@ -987,8 +954,8 @@ class mail_thread(osv.Model): uid instead """ to_unsubscribe_uids = [uid] if user_ids is None else user_ids - write_res = self.write(cr, uid, ids, {'message_subscriber_ids': [(3, id) for id in to_unsubscribe_uids]}, context=context) - return [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_subscriber_ids] + write_res = self.write(cr, uid, ids, {'message_follower_ids': [(3, id) for id in to_unsubscribe_uids]}, context=context) + return [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_follower_ids] #------------------------------------------------------ # Notification API From 9a3680e7f556ca20b6149cdff4555e141321c32f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 13 Aug 2012 21:15:01 +0200 Subject: [PATCH 11/72] [REF] mail: init and openerp files updated with followers instead of subscription. bzr revid: tde@openerp.com-20120813191501-tapi42znpz9bckiy --- addons/mail/__init__.py | 2 +- addons/mail/__openerp__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/mail/__init__.py b/addons/mail/__init__.py index cef9fe126aa..6e3baad57a8 100644 --- a/addons/mail/__init__.py +++ b/addons/mail/__init__.py @@ -21,7 +21,7 @@ import mail_alias import mail_message -import mail_subscription +import mail_followers import mail_thread import mail_group import ir_needaction diff --git a/addons/mail/__openerp__.py b/addons/mail/__openerp__.py index 5c9e4fdf1f8..0e1caabcf65 100644 --- a/addons/mail/__openerp__.py +++ b/addons/mail/__openerp__.py @@ -64,7 +64,7 @@ The main features of the module are: 'wizard/mail_compose_message_view.xml', 'res_config_view.xml', 'mail_message_view.xml', - 'mail_subscription_view.xml', + 'mail_followers_view.xml', 'mail_thread_view.xml', 'mail_group_view.xml', 'res_partner_view.xml', From c14a28fd934eec186c51220574e3e30e5409aa0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 13 Aug 2012 21:24:27 +0200 Subject: [PATCH 12/72] [MISC] mail_thread: updated one comment. bzr revid: tde@openerp.com-20120813192427-vw2id9wtd1hil9as --- 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 d82158ec3b3..f6303fca841 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -927,7 +927,7 @@ class mail_thread(osv.Model): def message_get_subscribers(self, cr, uid, ids, context=None): """ Returns the current document followers. Basically this method - checks in mail.subscription for entries with matching res_model, + checks in mail.followers for entries with matching res_model, res_id. """ subscr_obj = self.pool.get('mail.followers') From a52b57acf4369a1b5652d31f7b0756c8e6701a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 13 Aug 2012 21:38:41 +0200 Subject: [PATCH 13/72] [REF] Still refactoring of names: propagated to security files. bzr revid: tde@openerp.com-20120813193841-yavky2odabj5li70 --- addons/mail/security/ir.model.access.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv index 3677d424c14..1979e2fec05 100644 --- a/addons/mail/security/ir.model.access.csv +++ b/addons/mail/security/ir.model.access.csv @@ -2,7 +2,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_mail_message_all,mail.message.all,model_mail_message,,1,0,0,0 access_mail_message_group_user,mail.message.group.user,model_mail_message,base.group_user,1,1,1,1 access_mail_thread,mail.thread,model_mail_thread,base.group_user,1,1,1,0 -access_mail_subscription_all,mail.subscription.all,model_mail_subscription,,1,1,1,1 +access_mail_followers_all,mail.followers.all,model_mail_followers,,1,1,1,1 access_mail_notification_all,mail.notification.all,model_mail_notification,,1,1,1,1 access_mail_group,mail.group,model_mail_group,base.group_user,1,1,1,1 access_mail_alias_user,mail.alias,model_mail_alias,base.group_user,1,1,1,0 From f6155e6fa071e85084d8db2f8c29238b9c73d092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 13 Aug 2012 21:39:10 +0200 Subject: [PATCH 14/72] [FIX] mail_followers_view: deleted read field from view, because was deleted from modele. bzr revid: tde@openerp.com-20120813193910-5rnsgm0wf3hikkss --- addons/mail/mail_followers_view.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/mail/mail_followers_view.xml b/addons/mail/mail_followers_view.xml index ebb7104c5b3..b324cfb1ae9 100644 --- a/addons/mail/mail_followers_view.xml +++ b/addons/mail/mail_followers_view.xml @@ -27,7 +27,6 @@ - From 882eff5556cfeca8a0e8611e1a87989e1bbe9ef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 13 Aug 2012 21:40:37 +0200 Subject: [PATCH 15/72] [REF] mail.group: continuing the refactoring. member_ids field deleted, because this is now a standard field on mail.thread. Updated view and methods accordingly. bzr revid: tde@openerp.com-20120813194037-qm2xamhgnos3gqpt --- addons/mail/mail_group.py | 30 ++++++++++-------------------- addons/mail/mail_group_view.xml | 2 +- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py index b850f1c29f7..fb7c0b53b29 100644 --- a/addons/mail/mail_group.py +++ b/addons/mail/mail_group.py @@ -57,25 +57,17 @@ class mail_group(osv.osv): def _set_image(self, cr, uid, id, name, value, args, context=None): return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context) - def get_member_ids(self, cr, uid, ids, field_names, args, context=None): + def get_followers_data(self, cr, uid, ids, field_names, args, context=None): if context is None: context = {} result = dict.fromkeys(ids) - for id in ids: - result[id] = {} - result[id]['member_ids'] = self.message_get_subscribers(cr, uid, [id], context=context) - result[id]['member_count'] = len(result[id]['member_ids']) - result[id]['is_subscriber'] = uid in result[id]['member_ids'] + for thread in self.browse(cr, uid, ids, context=context): + result[thread.id] = { + 'member_count': len(thread.message_follower_ids), + 'is_subscriber': uid in [follower.id for follower in thread.message_follower_ids], + } return result - def search_member_ids(self, cr, uid, obj, name, args, context=None): - if context is None: - context = {} - sub_obj = self.pool.get('mail.subscription') - sub_ids = sub_obj.search(cr, uid, ['&', ('res_model', '=', obj._name), ('user_id', '=', args[0][2])], context=context) - subs = sub_obj.read(cr, uid, sub_ids, context=context) - return [('id', 'in', map(itemgetter('res_id'), subs))] - def get_last_month_msg_nbr(self, cr, uid, ids, name, args, context=None): result = {} message_obj = self.pool.get('mail.message') @@ -121,12 +113,10 @@ class mail_group(osv.osv): help="Small-sized photo of the group. It is automatically "\ "resized as a 50x50px image, with aspect ratio preserved. "\ "Use this field anywhere a small image is required."), - 'member_ids': fields.function(get_member_ids, fnct_search=search_member_ids, - type='many2many', relation='res.users', string='Group members', multi='get_member_ids'), - 'member_count': fields.function(get_member_ids, type='integer', - string='Member count', multi='get_member_ids'), - 'is_subscriber': fields.function(get_member_ids, type='boolean', - string='Joined', multi='get_member_ids'), + 'member_count': fields.function(get_followers_data, type='integer', + string='Member count', multi='get_followers_data'), + 'is_subscriber': fields.function(get_followers_data, type='boolean', + string='Joined', multi='get_followers_data'), 'last_month_msg_nbr': fields.function(get_last_month_msg_nbr, type='integer', string='Messages count for last month'), 'alias_id': fields.many2one('mail.alias', 'Alias', ondelete="cascade", required=True, diff --git a/addons/mail/mail_group_view.xml b/addons/mail/mail_group_view.xml index 9facf51febe..92fdd795359 100644 --- a/addons/mail/mail_group_view.xml +++ b/addons/mail/mail_group_view.xml @@ -82,7 +82,7 @@
-
From 2ae73a76154969a03656f5565a0044a01343946c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 13 Aug 2012 21:41:15 +0200 Subject: [PATCH 16/72] [REF] mail_thread: updated message_ids and message_summary computation due to changes in followers. bzr revid: tde@openerp.com-20120813194115-j125ubffz7alghzv --- addons/mail/mail_thread.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index f6303fca841..1e91b73cae5 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -112,13 +112,11 @@ class mail_thread(osv.Model): _description = 'Email Thread' def _get_message_ids(self, cr, uid, ids, name, args, context=None): - res = {} + res = dict.fromkeys(ids) + for id in ids: + res[id] = {'message_ids': self.message_search(cr, uid, [id], context=context)} for thread in self.browse(cr, uid, ids, context=context): - message_ids = self.message_search(cr, uid, [thread.id], context=context) - res[id] = { - 'message_ids': message_ids, - 'message_summary': "9 %d + %d" % (len(message_ids), len(thread.message_follower_ids)), - } + res[thread.id]['message_summary'] = "9 %d + %d" % (len(res[thread.id]['message_ids']), len(thread.message_follower_ids)) return res def _search_message_ids(self, cr, uid, obj, name, args, context=None): @@ -203,7 +201,7 @@ class mail_thread(osv.Model): self.message_subscribe(cr, uid, [thread_id], [vals['user_id']], context=context) # create message - msg_id = message_obj.create(cr, uid, vals, context=context) + msg_id = self.pool.get('mail.message').create(cr, uid, vals, context=context) # Set as unread if writer is not the document responsible self.message_create_set_unread(cr, uid, [thread_id], context=context) @@ -218,7 +216,7 @@ class mail_thread(osv.Model): notification_obj.create(cr, uid, {'user_id': id, 'message_id': msg_id}, context=context) # create the email to send - email_id = self.message_create_notify_by_email(cr, uid, vals, user_to_push_ids, context=context) + self.message_create_notify_by_email(cr, uid, vals, user_to_push_ids, context=context) return msg_id From f397e44b2f2c23cb4ffb696c82e97f4a16f9b2f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 13 Aug 2012 21:54:19 +0200 Subject: [PATCH 17/72] [FIX] portal: mail_subscription -> mail_followers. bzr revid: tde@openerp.com-20120813195419-c1j3r95wyj7fb0hj --- addons/portal/security/ir.model.access.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/portal/security/ir.model.access.csv b/addons/portal/security/ir.model.access.csv index 37302891333..56b3ae5f269 100644 --- a/addons/portal/security/ir.model.access.csv +++ b/addons/portal/security/ir.model.access.csv @@ -6,7 +6,7 @@ access_widget_manager,access.portal.widget.manager,model_res_portal_widget,group access_mail_message,mail.message,mail.model_mail_message,group_portal_member,1,0,1,1 access_mail_message_all,mail.message.all,mail.model_mail_message,group_portal_member,1,0,0,0 access_mail_thread,mail.thread,mail.model_mail_thread,group_portal_member,1,0,0,0 -access_mail_subscription,mail.subscription,mail.model_mail_subscription,group_portal_member,1,0,1,1 +access_mail_followers,mail.followers,mail.model_mail_followers,group_portal_member,1,0,1,1 access_mail_notification,mail.notification,mail.model_mail_notification,group_portal_member,1,0,1,0 access_mail_group,mail.group,mail.model_mail_group,group_portal_member,1,0,0,0 access_mail_alias,mail.alias,mail.model_mail_alias,group_portal_member,1,0,0,0 From 70f8659e7876a8b2a1ec64fac1d2f22a1d21f9e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 14 Aug 2012 13:39:37 +0200 Subject: [PATCH 18/72] [IMP] mail_thread: method to calculate mail values is now _get_message_data; added message_is_follower field, with its computation; cleaned a bit the code. bzr revid: tde@openerp.com-20120814113937-a7279ud2rj5fixl9 --- addons/mail/mail_thread.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index fbbac88639b..efba082fee4 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -106,17 +106,22 @@ class mail_thread(osv.Model): methods (calling ``super``) to add model-specific behavior at creation and update of a thread. - TODO: UPDATE WITIH SUBTYPE / NEW FOLLOW MECHANISM + #TODO: UPDATE WITH SUBTYPE / NEW FOLLOW MECHANISM ''' _name = 'mail.thread' _description = 'Email Thread' - def _get_message_ids(self, cr, uid, ids, name, args, context=None): + def _get_message_data(self, cr, uid, ids, field_names, args, context=None): res = dict.fromkeys(ids) for id in ids: res[id] = {'message_ids': self.message_search(cr, uid, [id], context=context)} for thread in self.browse(cr, uid, ids, context=context): - res[thread.id]['message_summary'] = "9 %d + %d" % (len(res[thread.id]['message_ids']), len(thread.message_follower_ids)) + message_follower_ids = [follower.id for follower in thread.message_follower_ids] + res[thread.id].update({ + 'message_is_follower': uid in message_follower_ids, + 'message_summary': "9 %d + %d" % + (len(res[thread.id]['message_ids']), len(thread.message_follower_ids)) + }) return res def _search_message_ids(self, cr, uid, obj, name, args, context=None): @@ -125,19 +130,22 @@ class mail_thread(osv.Model): return [('id', 'in', msg_ids)] _columns = { - 'message_ids': fields.function(_get_message_ids, + 'message_ids': fields.function(_get_message_data, fnct_search=_search_message_ids, type='one2many', obj='mail.message', _fields_id = 'res_id', - string='Temp messages', multi="_get_message_ids", + string='Temp messages', multi="_get_message_data", help="Functional field holding messages related to the current document."), 'message_follower_ids': many2many_reference('res.users', rel='mail_followers', id1='res_id', id2='user_id', string="Followers", help="Followers of the document. The followers have full access to " \ "the document details, as well as the conversation."), + 'message_is_follower': fields.function(_get_message_data, method=True, + type='boolean', string='I am Follower', multi='_get_message_data', + help='True if the current user is following the current document.'), 'message_state': fields.boolean('Read', help="When checked, new messages require your attention."), - 'message_summary': fields.function(_get_message_ids, method=True, - type='text', string='Summary', multi="_get_message_ids", + 'message_summary': fields.function(_get_message_data, method=True, + type='text', string='Summary', multi='_get_message_data', help="Holds the Chatter summary (number of messages, ...). "\ "This summary is directly in html format in order to "\ "be inserted in kanban views."), From 4dd85980ec251de04343e2330997b1a4b14e5895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 14 Aug 2012 13:40:21 +0200 Subject: [PATCH 19/72] [IMP] mail_group: removed fields now delegated to mail_thread; updated doc and kanban view accordingly. bzr revid: tde@openerp.com-20120814114021-vwiz24yu2mo75jt7 --- addons/mail/mail_group.py | 27 +++------------------------ addons/mail/mail_group_view.xml | 14 +++++++++----- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py index fb7c0b53b29..82dcb4bc50b 100644 --- a/addons/mail/mail_group.py +++ b/addons/mail/mail_group.py @@ -29,18 +29,12 @@ import tools from tools.translate import _ from lxml import etree -class mail_group(osv.osv): +class mail_group(osv.Model): """ A mail_group is a collection of users sharing messages in a discussion group. Group users are users that follow the mail group, using the subscription/follow mechanism of OpenSocial. A mail group has nothing in common with res.users.group. - Additional information on fields: - - ``member_ids``: user member of the groups are calculated with - ``message_get_subscribers`` method from mail.thread - - ``member_count``: calculated with member_ids - - ``is_subscriber``: calculated with member_ids - """ _description = 'Discussion group' @@ -57,18 +51,7 @@ class mail_group(osv.osv): def _set_image(self, cr, uid, id, name, value, args, context=None): return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context) - def get_followers_data(self, cr, uid, ids, field_names, args, context=None): - if context is None: - context = {} - result = dict.fromkeys(ids) - for thread in self.browse(cr, uid, ids, context=context): - result[thread.id] = { - 'member_count': len(thread.message_follower_ids), - 'is_subscriber': uid in [follower.id for follower in thread.message_follower_ids], - } - return result - - def get_last_month_msg_nbr(self, cr, uid, ids, name, args, context=None): + def _get_last_month_msg_nbr(self, cr, uid, ids, name, args, context=None): result = {} message_obj = self.pool.get('mail.message') for id in ids: @@ -113,11 +96,7 @@ class mail_group(osv.osv): help="Small-sized photo of the group. It is automatically "\ "resized as a 50x50px image, with aspect ratio preserved. "\ "Use this field anywhere a small image is required."), - 'member_count': fields.function(get_followers_data, type='integer', - string='Member count', multi='get_followers_data'), - 'is_subscriber': fields.function(get_followers_data, type='boolean', - string='Joined', multi='get_followers_data'), - 'last_month_msg_nbr': fields.function(get_last_month_msg_nbr, type='integer', + 'last_month_msg_nbr': fields.function(_get_last_month_msg_nbr, type='integer', string='Messages count for last month'), 'alias_id': fields.many2one('mail.alias', 'Alias', ondelete="cascade", required=True, help="The email address associated with this group. New emails received will automatically " diff --git a/addons/mail/mail_group_view.xml b/addons/mail/mail_group_view.xml index 92fdd795359..4f25ba300be 100644 --- a/addons/mail/mail_group_view.xml +++ b/addons/mail/mail_group_view.xml @@ -10,6 +10,8 @@ + +
@@ -17,17 +19,19 @@
-
+

-
From 19abc35ce640fae67dc13126c829913e93f4158a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 14 Aug 2012 13:52:22 +0200 Subject: [PATCH 20/72] [CLEAN] Cleaned mail_group and mail.js due to the merge of trunk. bzr revid: tde@openerp.com-20120814115222-gxunwfuttejrock0 --- addons/mail/mail_group.py | 12 ++++++------ addons/mail/static/src/js/mail.js | 2 -- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py index d9519caf6d3..84008548d96 100644 --- a/addons/mail/mail_group.py +++ b/addons/mail/mail_group.py @@ -64,21 +64,21 @@ class mail_group(osv.Model): return tools.image_resize_image_big(open(image_path, 'rb').read().encode('base64')) _columns = { - #'name': fields.char('Group Name', size=64, required=True), 'description': fields.text('Description'), 'menu_id': fields.many2one('ir.ui.menu', string='Related Menu', required=True, ondelete="cascade"), 'responsible_id': fields.many2one('res.users', string='Responsible', ondelete='set null', required=True, select=1, help="Responsible of the group that has all rights on the record."), - 'public': fields.selection([('public','Public'),('private','Private'),('groups','Selected Group Only')], 'Privacy', required=True, - help='This group is visible by non members. \ - Invisible groups can add members through the invite button.'), + 'public': fields.selection([('public', 'Public'), ('private', 'Private'), ('groups', 'Selected Group Only')], + string='Privacy', required=True, + help='This group is visible by non members. '\ + 'Invisible groups can add members through the invite button.'), 'group_public_id': fields.many2one('res.groups', string='Authorized Group'), 'group_ids': fields.many2many('res.groups', rel='mail_group_res_group_rel', id1='mail_group_id', id2='groups_id', string='Auto Subscription', help="Members of those groups will automatically added as followers. "\ - "Note that they will be able to manage their subscription manually "\ - "if necessary."), + "Note that they will be able to manage their subscription manually "\ + "if necessary."), 'image': fields.binary("Photo", help="This field holds the image used as photo for the "\ "user. The image is base64 encoded, and PIL-supported. "\ diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 500d0b9c138..16404b28594 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -911,7 +911,6 @@ openerp.mail = function(session) { this.params.res_id = params.res_id || false; this.params.search_view_id = params.search_view_id || false; this.params.thread_level = params.thread_level || 1; - this.params.title = params.title || false; this.comments_structure = {'root_ids': [], 'new_root_ids': [], 'msgs': {}, 'tree_struct': {}, 'model_to_root_ids': {}}; this.display_show_more = true; this.thread_list = []; @@ -956,7 +955,6 @@ openerp.mail = function(session) { if (this.compose_message_widget) { this.compose_message_widget.destroy(); } - debugger; this.compose_message_widget = new mail.ComposeMessage(this, { 'extended_mode': false, 'uid': this.session.uid, 'res_model': this.params.res_model, 'res_id': this.params.res_id, 'mode': mode || 'comment', 'msg_id': msg_id }); From 89e404301bdaa57dc2bbe351bfefac993ade9b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 14 Aug 2012 14:12:02 +0200 Subject: [PATCH 21/72] [CLEAN] mail_group_menu: cleaned file, added some doc. bzr revid: tde@openerp.com-20120814121202-zuhu88g95p78ggdc --- addons/mail/mail_group_menu.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/addons/mail/mail_group_menu.py b/addons/mail/mail_group_menu.py index 38756f69928..8625285d640 100644 --- a/addons/mail/mail_group_menu.py +++ b/addons/mail/mail_group_menu.py @@ -2,7 +2,7 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2010-today OpenERP SA () +# Copyright (C) 2012-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 @@ -24,21 +24,29 @@ from osv import fields from tools.translate import _ class ir_ui_menu(osv.osv): + """ Override of ir.ui.menu class. When adding mail_thread module, each + new mail.group will create a menu entry. This overrides checks that + the current user is in the mail.group followers. If not, the menu + entry is taken off the list of menu ids. This way the user will see + menu entries for the mail.group he is following. + """ _inherit = 'ir.ui.menu' + _columns = { 'mail_group_id': fields.many2one('mail.group', 'Mail Group') } - def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False): - ids = super(ir_ui_menu, self).search(cr, uid, args, offset=0, limit=None, order=order, context=context, count=False) - subs = self.pool.get('mail.subscription') + def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False): + """ Override to take off menu entries (mail.group) the user is not + following. """ + ids = super(ir_ui_menu, self).search(cr, uid, args, offset=0, limit=None, order=order, context=context, count=False) + follower_obj = self.pool.get('mail.followers') for menu in self.browse(cr, uid, ids, context=context): if menu.mail_group_id: - sub_ids = subs.search(cr, uid, [ - ('user_id','=',uid),('res_model','=','mail.group'), - ('res_id','=',menu.mail_group_id.id) + sub_ids = follower_obj.search(cr, uid, [ + ('user_id', '=', uid), ('res_model', '=', 'mail.group'), + ('res_id', '=', menu.mail_group_id.id) ], context=context) if not sub_ids: ids.remove(menu.id) return ids - From a6482fe07c57805976529eebd48225b060a9a49c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 14 Aug 2012 19:06:12 +0200 Subject: [PATCH 22/72] [WIP] Followers rewrite: in create/write, the purpose is to add the field in the values to write, and to simplify automatic subscription. WIP, lack of time to finish. Will be continued. bzr revid: tde@openerp.com-20120814170612-ax8xhcmmttrcphnl --- addons/crm/crm_lead.py | 11 ++-- addons/hr_holidays/hr_holidays.py | 13 ++-- addons/hr_recruitment/hr_recruitment.py | 11 ++-- addons/mail/mail_group.py | 9 +++ addons/mail/mail_thread.py | 79 +++++++++++++++++++++++-- addons/mrp/mrp.py | 11 ++-- addons/project/project.py | 24 +++----- addons/project_issue/project_issue.py | 11 ++-- 8 files changed, 111 insertions(+), 58 deletions(-) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 6e1d3a7755b..6b29dbbafe6 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -859,13 +859,10 @@ class crm_lead(base_stage, osv.osv): # OpenChatter methods and notifications # ---------------------------------------- - def message_get_subscribers(self, cr, uid, ids, context=None): - """ Override to add the salesman. """ - user_ids = super(crm_lead, self).message_get_subscribers(cr, uid, ids, context=context) - for obj in self.browse(cr, uid, ids, context=context): - if obj.user_id and not obj.user_id.id in user_ids: - user_ids.append(obj.user_id.id) - return user_ids + def message_get_follower_fields(self, cr, uid, ids, context=None): + """ Override to add 'user_id' field to automatic subscription. """ + res = super(crm_lead, self).message_get_follower_fields(cr, uid, ids, context=context) + return res.append('user_id') def stage_set_send_note(self, cr, uid, ids, stage_id, context=None): """ Override of the (void) default notification method. """ diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index 7eedfa54ce5..1788c857aba 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -366,15 +366,10 @@ class hr_holidays(osv.osv): result[obj.id] = hr_manager_group['users'] return result - def message_get_subscribers(self, cr, uid, ids, context=None): - """ Override to add employee and its manager. """ - user_ids = super(hr_holidays, self).message_get_subscribers(cr, uid, ids, context=context) - for obj in self.browse(cr, uid, ids, context=context): - if obj.user_id and not obj.user_id.id in user_ids: - user_ids.append(obj.user_id.id) - if obj.employee_id.parent_id and not obj.employee_id.parent_id.user_id.id in user_ids: - user_ids.append(obj.employee_id.parent_id.user_id.id) - return user_ids + def message_get_follower_fields(self, cr, uid, ids, context=None): + """ Override to add 'user_id' field to automatic subscription. """ + res = super(hr_holidays, self).message_get_follower_fields(cr, uid, ids, context=context) + return res + ['user_id', 'employee_id.parent_id.user_id'] def create_notificate(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids, context=context): diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index 1db79172dc5..cdd3252ff49 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -461,13 +461,10 @@ class hr_applicant(base_stage, osv.Model): # OpenChatter methods and notifications # ------------------------------------------------------- - def message_get_subscribers(self, cr, uid, ids, context=None): - """ Override to add responsible user. """ - user_ids = super(hr_applicant, self).message_get_subscribers(cr, uid, ids, context=context) - for obj in self.browse(cr, uid, ids, context=context): - if obj.user_id and not obj.user_id.id in user_ids: - user_ids.append(obj.user_id.id) - return user_ids + def message_get_follower_fields(self, cr, uid, ids, context=None): + """ Override to add 'user_id' field to automatic subscription. """ + res = super(hr_applicant, self).message_get_follower_fields(cr, uid, ids, context=context) + return res.append('user_id') def stage_set_send_note(self, cr, uid, ids, stage_id, context=None): """ Override of the (void) default notification method. """ diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py index 84008548d96..306a758eda2 100644 --- a/addons/mail/mail_group.py +++ b/addons/mail/mail_group.py @@ -184,3 +184,12 @@ class mail_group(osv.Model): def action_group_leave(self, cr, uid, ids, context=None): return self.message_unsubscribe(cr, uid, ids, context=context) + + # ---------------------------------------- + # OpenChatter methods and notifications + # ---------------------------------------- + + def message_get_monitored_follower_fields(self, cr, uid, ids, context=None): + """ Add 'responsible_id' to the monitored fields """ + res = super(mail_group, self).message_get_monitored_follower_fields(cr, uid, ids, context=context) + return res + ['responsible_id'] diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index efba082fee4..473dffe21fd 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -35,6 +35,10 @@ import xmlrpclib _logger = logging.getLogger(__name__) class many2many_reference(fields.many2many): + """ many2many_reference is an override of fields.many2many. It manages + many2many-like table where one id is given by two fields, res_model + and res_id. + """ def _get_query_and_where_params(self, cr, model, ids, values, where_params): """ Add in where: @@ -54,6 +58,7 @@ class many2many_reference(fields.many2many): return query, where_params def set(self, cr, model, id, name, values, user=None, context=None): + """ Override to add the res_model field in queries. """ if not values: return rel, id1, id2 = self._sql_names(model) obj = model.pool.get(self._obj) @@ -64,7 +69,7 @@ class many2many_reference(fields.many2many): idnew = obj.create(cr, user, act[2], context=context) cr.execute('INSERT INTO '+rel+' ('+id1+','+id2+',res_model) VALUES (%s,%s,%s)', (id, idnew, model._name)) elif act[0] == 3: - cr.execute('DELETE FROM "'+rel+'" WHERE '+id1+'=%s AND '+id2+'=%s AND res_model=%s', (id, act[1], model._name)) + cr.execute('DELETE FROM '+rel+' WHERE '+id1+'=%s AND '+id2+'=%s AND res_model=%s', (id, act[1], model._name)) elif act[0] == 4: # following queries are in the same transaction - so should be relatively safe cr.execute('SELECT 1 FROM '+rel+' WHERE '+id1+'=%s AND '+id2+'=%s AND res_model=%s', (id, act[1], model._name)) @@ -80,7 +85,6 @@ class many2many_reference(fields.many2many): for act_nbr in act[2]: cr.execute('INSERT INTO '+rel+' ('+id1+','+id2+',res_model) VALUES (%s,%s,%s)', (id, act_nbr, model._name)) else: - print act return super(many2many_reference, self).set(cr, model, id, name, values, user, context) class mail_thread(osv.Model): @@ -160,18 +164,36 @@ class mail_thread(osv.Model): #------------------------------------------------------ def create(self, cr, uid, vals, context=None): - """ Automatically subscribe the creator """ + """ Override of create to subscribe : + - the writer + - followers given by the monitored fields + """ thread_id = super(mail_thread, self).create(cr, uid, vals, context=context) + fields = self.message_get_follower_fields(cr, uid, [thread_id], context=context) + print fields if thread_id: self.message_subscribe(cr, uid, [thread_id], [uid], context=context) return thread_id def write(self, cr, uid, ids, vals, context=None): - """ Override of write to subscribe the writer, except if he has changed - the followers (to avoid unfollow-->follow). """ + """ Override of write to subscribe : + - the writer + - followers given by the monitored fields + """ if isinstance(ids, (int, long)): ids = [ids] + command = self.message_get_automatic_followers(cr, uid, ids, vals, context=context) + print command + if vals.get('message_follower_ids'): + vals['message_follower_ids'] += command + else: + vals['message_follower_ids'] = command + print vals write_res = super(mail_thread, self).write(cr, uid, ids, vals, context=context) + + + + if write_res and not vals.get('message_follower_ids'): self.message_subscribe(cr, uid, ids, [uid], context=context) return write_res; @@ -188,6 +210,39 @@ class mail_thread(osv.Model): msg_obj.unlink(cr, uid, msg_to_del_ids, context=context) return super(mail_thread, self).unlink(cr, uid, ids, context=context) + def message_get_automatic_followers(self, cr, uid, ids, record_vals, add_uid=True, fetch_missing=False, context=None): + """ + + :param record_vals: values given to the create method of the new + record, or values updated in a write. + :param monitored_fields: a list of fields that are monitored. Those + fields must be many2one fields to the res.users model. + :param fetch_missing: is set to True, the method will read the + record to find values that are not present in record_vals. + + #TODO : UPDATE WHEN MERGING TO PARTNERS + """ + # get monitored fields + monitored_fields = self.message_get_monitored_follower_fields(cr, uid, ids, context=context) + print monitored_fields + # for each monitored field: if in record_vals, it has been modified + fields = [field for field in monitored_fields if field in record_vals.iterkeys()] + print fields + + follower_ids = [] + for field in fields: + value = record_vals.get(field) + if value: + follower_ids.append(value) + elif fetch_missing: + pass + + print follower_ids + if add_uid and uid not in follower_ids: + follower_ids.append(uid) + + return self.message_subscribe_get_command(cr, uid, follower_ids, context=context) + #------------------------------------------------------ # mail.message wrappers and tools #------------------------------------------------------ @@ -931,6 +986,12 @@ class mail_thread(osv.Model): # Subscription mechanism #------------------------------------------------------ + def message_get_monitored_follower_fields(self, cr, uid, ids, context=None): + """ Returns a list of fields containing a res.user.id. Those fields + will be checked to automatically subscribe those users. + """ + return [] + def message_get_subscribers(self, cr, uid, ids, context=None): """ Returns the current document followers. Basically this method checks in mail.followers for entries with matching res_model, @@ -953,6 +1014,10 @@ class mail_thread(osv.Model): write_res = self.write(cr, uid, ids, {'message_follower_ids': [(4, id) for id in to_subscribe_uids]}, context=context) return [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_follower_ids] + def message_subscribe_get_command(self, cr, uid, follower_ids, context=None): + """ Generate the many2many command to add followers. """ + return [(4, id) for id in follower_ids] + def message_unsubscribe(self, cr, uid, ids, user_ids = None, context=None): """ Unsubscribe the user (or user_ids) from the current document. @@ -963,6 +1028,10 @@ class mail_thread(osv.Model): write_res = self.write(cr, uid, ids, {'message_follower_ids': [(3, id) for id in to_unsubscribe_uids]}, context=context) return [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_follower_ids] + def message_unsubscribe_get_command(self, cr, uid, follower_ids, context=None): + """ Generate the many2many command to remove followers. """ + return [(3, id) for id in follower_ids] + #------------------------------------------------------ # Notification API #------------------------------------------------------ diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 749d95c0c23..a41e4dbc332 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -1046,13 +1046,10 @@ class mrp_production(osv.osv): # OpenChatter methods and notifications # --------------------------------------------------- - def message_get_subscribers(self, cr, uid, ids, context=None): - """ Override to add responsible user. """ - user_ids = super(mrp_production, self).message_get_subscribers(cr, uid, ids, context=context) - for obj in self.browse(cr, uid, ids, context=context): - if obj.user_id and not obj.user_id.id in user_ids: - user_ids.append(obj.user_id.id) - return user_ids + def message_get_follower_fields(self, cr, uid, ids, context=None): + """ Override to add 'user_id' field to automatic subscription. """ + res = super(mrp_production, self).message_get_follower_fields(cr, uid, ids, context=context) + return res.append('user_id') def create_send_note(self, cr, uid, ids, context=None): self.message_append_note(cr, uid, ids, body=_("Manufacturing order has been created."), context=context) diff --git a/addons/project/project.py b/addons/project/project.py index 6f3b23f4746..b1db7fde6b3 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -513,13 +513,10 @@ def Project(): # OpenChatter methods and notifications # ------------------------------------------------ - def message_get_subscribers(self, cr, uid, ids, context=None): - """ Override to add responsible user. """ - user_ids = super(project, self).message_get_subscribers(cr, uid, ids, context=context) - for obj in self.browse(cr, uid, ids, context=context): - if obj.user_id and not obj.user_id.id in user_ids: - user_ids.append(obj.user_id.id) - return user_ids + def message_get_follower_fields(self, cr, uid, ids, context=None): + """ Override to add 'user_id' field to automatic subscription. """ + res = super(project, self).message_get_follower_fields(cr, uid, ids, context=context) + return res.append('user_id') def create(self, cr, uid, vals, context=None): if context is None: context = {} @@ -1201,15 +1198,10 @@ class task(base_stage, osv.osv): result[obj.id].append(obj.user_id.id) return result - def message_get_subscribers(self, cr, uid, ids, context=None): - """ Override to add responsible user and project manager. """ - user_ids = super(task, self).message_get_subscribers(cr, uid, ids, context=context) - for obj in self.browse(cr, uid, ids, context=context): - if obj.user_id and not obj.user_id.id in user_ids: - user_ids.append(obj.user_id.id) - if obj.manager_id and not obj.manager_id.id in user_ids: - user_ids.append(obj.manager_id.id) - return user_ids + def message_get_follower_fields(self, cr, uid, ids, context=None): + """ Override to add 'user_id' field to automatic subscription. """ + res = super(task, self).message_get_follower_fields(cr, uid, ids, context=context) + return res + ['user_id', 'manager_id'] def stage_set_send_note(self, cr, uid, ids, stage_id, context=None): """ Override of the (void) default notification method. """ diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py index 7b2afbeacf2..5aa34c173c5 100644 --- a/addons/project_issue/project_issue.py +++ b/addons/project_issue/project_issue.py @@ -502,13 +502,10 @@ class project_issue(base_stage, osv.osv): # OpenChatter methods and notifications # ------------------------------------------------------- - def message_get_subscribers(self, cr, uid, ids, context=None): - """ Override to add responsible user. """ - user_ids = super(project_issue, self).message_get_subscribers(cr, uid, ids, context=context) - for obj in self.browse(cr, uid, ids, context=context): - if obj.user_id and not obj.user_id.id in user_ids: - user_ids.append(obj.user_id.id) - return user_ids + def message_get_follower_fields(self, cr, uid, ids, context=None): + """ Override to add 'user_id' field to automatic subscription. """ + res = super(project_issue, self).message_get_follower_fields(cr, uid, ids, context=context) + return res.append('user_id') def stage_set_send_note(self, cr, uid, ids, stage_id, context=None): """ Override of the (void) default notification method. """ From 2b0fcb77753bda709a1abf6995874469985fd595 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Tue, 14 Aug 2012 21:53:16 +0200 Subject: [PATCH 23/72] [WIP] groups drag'n drop + resequence bzr revid: fme@openerp.com-20120814195316-j66wn6yxta6yj0w9 --- addons/web/controllers/main.py | 6 ++ addons/web/static/src/js/data.js | 16 +++++ addons/web_kanban/static/src/css/kanban.css | 4 ++ addons/web_kanban/static/src/css/kanban.sass | 2 + addons/web_kanban/static/src/js/kanban.js | 71 +++++++++++++++++-- .../web_kanban/static/src/xml/web_kanban.xml | 4 ++ 6 files changed, 97 insertions(+), 6 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index c5fdcce4945..e2ba9ebc5cc 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1136,6 +1136,12 @@ class DataSet(openerpweb.Controller): def exec_workflow(self, req, model, id, signal): return req.session.exec_workflow(model, id, signal) + @openerpweb.jsonrequest + def resequence(self, req, model, ids): + m = req.session.model(model) + print "TODO: write resequencing" + return True + class DataGroup(openerpweb.Controller): _cp_path = "/web/group" @openerpweb.jsonrequest diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index e360c922918..a2adc2429bd 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -805,6 +805,22 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend( /** @lends openerp. alter_ids: function(n_ids) { this.ids = n_ids; }, + /** + * Resequence records. + * + * @param {Array} ids identifiers of the records to resequence + * @returns {$.Deferred} + */ + resequence: function (ids, options) { + options = options || {}; + return this.rpc('/web/dataset/resequence', { + model: this.model, + ids: ids, + context: this._model.context(options.context), + }).pipe(function (results) { + return results; + }); + }, }); instance.web.DataSetStatic = instance.web.DataSet.extend({ init: function(parent, model, context, ids) { diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index 47d9368d9dc..5b4d18c2e71 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -1,3 +1,4 @@ +@charset "utf-8"; .openerp .oe_kanban_view { height: inherit; } @@ -44,6 +45,9 @@ .openerp .oe_kanban_view.oe_kanban_ungrouped .oe_kanban_groups { width: 100%; } +.openerp .oe_kanban_view.oe_kanban_sortable_groups .oe_kanban_group_title { + cursor: move; +} .openerp .oe_kanban_view .oe_kanban_header:hover .oe_dropdown_kanban { display: inline-block; } diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass index 029014b1f43..c1a8f48645d 100644 --- a/addons/web_kanban/static/src/css/kanban.sass +++ b/addons/web_kanban/static/src/css/kanban.sass @@ -66,6 +66,8 @@ height: inherit &.oe_kanban_ungrouped .oe_kanban_groups width: 100% + &.oe_kanban_sortable_groups .oe_kanban_group_title + cursor: move .oe_kanban_header &:hover .oe_dropdown_kanban diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 6c70ecfb8ec..4ca7ebf2be9 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -24,6 +24,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ this.fields_view = {}; this.fields_keys = []; this.group_by = null; + this.grouped_by_m2o = false; this.state = { groups : {}, records : {} @@ -54,7 +55,8 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ this.$element.find('.oe_kanban_buttons').replaceWith(this.$buttons); } this.$buttons - .on('click','button.oe_kanban_button_new', this.do_add_record); + .on('click', 'button.oe_kanban_button_new', this.do_add_record) + .on('click', '.oe_kanban_add_column', this.do_add_group); this.$groups = this.$element.find('.oe_kanban_groups tr'); this.fields_keys = _.keys(this.fields_view.fields); this.add_qweb_template(); @@ -157,6 +159,27 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ this.dataset.index = null; this.do_switch_view('form'); }, + do_add_group: function() { + var self = this; + var group_by = self.fields_view.fields[self.group_by]; + self.do_action({ + name: _t("Add column"), + res_model: group_by.relation, + views: [[false, 'form']], + type: 'ir.actions.act_window', + target: "new", + flags: { + action_buttons: true, + } + }); + var am = instance.webclient.action_manager; + var form = am.dialog_widget.views.form.controller; + form.on_button_cancel.add_last(am.dialog.on_close); + form.on_created.add_last(function() { + am.dialog.on_close(); + self.do_reload(); + }); + }, do_search: function(domain, context, group_by) { var self = this; this.$element.find('.oe_view_nocontent').remove(); @@ -165,6 +188,10 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ this.search_group_by = group_by; $.when(this.has_been_loaded).then(function() { self.group_by = group_by.length ? group_by[0] : self.fields_view.arch.attrs.default_group_by; + var group_by_field = self.fields_view.fields[self.group_by]; + self.grouped_by_m2o = !!(group_by_field && group_by_field.type === 'many2one'); + self.$buttons.find('.oe_alternative').toggle(self.grouped_by_m2o); + self.$element.toggleClass('oe_kanban_sortable_groups', self.grouped_by_m2o); self.datagroup = new instance.web.DataGroup(self, self.dataset.model, domain, context, self.group_by ? [self.group_by] : []); self.datagroup.list(self.fields_keys, self.do_process_groups, self.do_process_dataset); }); @@ -237,6 +264,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ var self = this; this.compute_groups_width(); if (this.group_by) { + // Kanban cards drag'n'drop this.$element.find('.oe_kanban_column').sortable({ connectWith: '.oe_kanban_column', handle : '.oe_kanban_draghandle', @@ -245,17 +273,48 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ self.currently_dragging.group = ui.item.parents('.oe_kanban_column:first').data('widget'); }, stop: function(event, ui) { - var record = ui.item.data('widget'), - old_index = self.currently_dragging.index, - new_index = ui.item.index(), - old_group = self.currently_dragging.group, - new_group = ui.item.parents('.oe_kanban_column:first').data('widget'); + var record = ui.item.data('widget'); + var old_index = self.currently_dragging.index; + var new_index = ui.item.index(); + var old_group = self.currently_dragging.group; + var new_group = ui.item.parents('.oe_kanban_column:first').data('widget'); if (!(old_group.title === new_group.title && old_group.value === new_group.value && old_index == new_index)) { self.on_record_moved(record, old_group, old_index, new_group, new_index); } }, scroll: false }); + // Kanban groups drag'n'drop + var start_index; + if (this.grouped_by_m2o) { + this.$('.oe_kanban_groups_headers').sortable({ + helper: 'clone', + axis: 'x', + opacity: 0.5, + scroll: false, + start: function(event, ui) { + start_index = ui.item.index(); + self.$('.oe_kanban_record').hide(); + }, + stop: function(event, ui) { + var stop_index = ui.item.index(); + if (start_index !== stop_index) { + var $start_column = $('.oe_kanban_groups_records .oe_kanban_column').eq(start_index); + var $stop_column = $('.oe_kanban_groups_records .oe_kanban_column').eq(stop_index); + var method = (start_index > stop_index) ? 'insertBefore' : 'insertAfter'; + $start_column[method]($stop_column); + var tmp_group = self.groups.splice(start_index, 1)[0]; + self.groups.splice(stop_index, 0, tmp_group); + var new_sequence = _.pluck(self.groups, 'value'); + var field = self.fields_view.fields[self.group_by]; //TODO: self.field should be the field definition + (new instance.web.DataSet(self, field.relation)).resequence(new_sequence).then(function(r) { + console.log(r); + }); + } + self.$('.oe_kanban_record').show(); + } + }); + } } else { this.$element.find('.oe_kanban_draghandle').removeClass('oe_kanban_draghandle'); } diff --git a/addons/web_kanban/static/src/xml/web_kanban.xml b/addons/web_kanban/static/src/xml/web_kanban.xml index 4bcc9a709a3..e1da07e3554 100644 --- a/addons/web_kanban/static/src/xml/web_kanban.xml +++ b/addons/web_kanban/static/src/xml/web_kanban.xml @@ -18,6 +18,10 @@ +
From cc406bc6920513faf960a29a500409985c1ee5bd Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Tue, 14 Aug 2012 23:37:08 +0200 Subject: [PATCH 24/72] [WIP] Added group_by_field bzr revid: fme@openerp.com-20120814213708-zkm05nkr1pdf8qbu --- addons/web/static/src/js/data.js | 2 +- addons/web_kanban/static/src/js/kanban.js | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index a2adc2429bd..2372c6bbff9 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -813,7 +813,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend( /** @lends openerp. */ resequence: function (ids, options) { options = options || {}; - return this.rpc('/web/dataset/resequence', { + return instance.session.rpc('/web/dataset/resequence', { model: this.model, ids: ids, context: this._model.context(options.context), diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 4ca7ebf2be9..42a3fc1600e 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -24,6 +24,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ this.fields_view = {}; this.fields_keys = []; this.group_by = null; + this.group_by_field = {}; this.grouped_by_m2o = false; this.state = { groups : {}, @@ -161,10 +162,9 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ }, do_add_group: function() { var self = this; - var group_by = self.fields_view.fields[self.group_by]; self.do_action({ name: _t("Add column"), - res_model: group_by.relation, + res_model: self.group_by_field.relation, views: [[false, 'form']], type: 'ir.actions.act_window', target: "new", @@ -188,8 +188,8 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ this.search_group_by = group_by; $.when(this.has_been_loaded).then(function() { self.group_by = group_by.length ? group_by[0] : self.fields_view.arch.attrs.default_group_by; - var group_by_field = self.fields_view.fields[self.group_by]; - self.grouped_by_m2o = !!(group_by_field && group_by_field.type === 'many2one'); + self.group_by_field = self.fields_view.fields[self.group_by] || {}; + self.grouped_by_m2o = (self.group_by_field.type === 'many2one'); self.$buttons.find('.oe_alternative').toggle(self.grouped_by_m2o); self.$element.toggleClass('oe_kanban_sortable_groups', self.grouped_by_m2o); self.datagroup = new instance.web.DataGroup(self, self.dataset.model, domain, context, self.group_by ? [self.group_by] : []); @@ -306,8 +306,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ var tmp_group = self.groups.splice(start_index, 1)[0]; self.groups.splice(stop_index, 0, tmp_group); var new_sequence = _.pluck(self.groups, 'value'); - var field = self.fields_view.fields[self.group_by]; //TODO: self.field should be the field definition - (new instance.web.DataSet(self, field.relation)).resequence(new_sequence).then(function(r) { + (new instance.web.DataSet(self, self.group_by_field.relation)).resequence(new_sequence).then(function(r) { console.log(r); }); } @@ -421,7 +420,7 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ this.title = this.value[1]; this.value = this.value[0]; } - var field = this.view.fields_view.fields[this.view.group_by]; + var field = this.view.group_by_field; if (field) { try { this.title = instance.web.format_value(group.value, field, false); From f1531572de0c3099ff78da65473dfc29dba6c4ac Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 15 Aug 2012 00:13:34 +0200 Subject: [PATCH 25/72] [WIP] Resequence bzr revid: fme@openerp.com-20120814221334-8arihwthpwictk3y --- addons/web/controllers/main.py | 5 ++++- addons/web_kanban/static/src/js/kanban.js | 9 +++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index e2ba9ebc5cc..4a7f09cb461 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1139,7 +1139,10 @@ class DataSet(openerpweb.Controller): @openerpweb.jsonrequest def resequence(self, req, model, ids): m = req.session.model(model) - print "TODO: write resequencing" + if not len(m.fields_get(['sequence'])): + return False + for i in range(len(ids)): + m.write([ids[i]], { 'sequence': i }) return True class DataGroup(openerpweb.Controller): diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 42a3fc1600e..245f7024a22 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -307,7 +307,9 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ self.groups.splice(stop_index, 0, tmp_group); var new_sequence = _.pluck(self.groups, 'value'); (new instance.web.DataSet(self, self.group_by_field.relation)).resequence(new_sequence).then(function(r) { - console.log(r); + if (r === false) { + console.error("Kanban: could not resequence model '%s'. Probably no 'sequence' field.", self.group_by_field.relation); + } }); } self.$('.oe_kanban_record').show(); @@ -555,9 +557,8 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ do_save_sequences: function() { var self = this; if (_.indexOf(this.view.fields_keys, 'sequence') > -1) { - _.each(this.records, function(record, index) { - self.view.dataset.write(record.id, { sequence : index }); - }); + var new_sequence = _.pluck(this.records, 'id'); + self.view.dataset.resequence(new_sequence); } }, /** From 4bdf1b6beae5c3f28c5542ab8405e4599c4727c5 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Wed, 15 Aug 2012 00:23:29 +0200 Subject: [PATCH 26/72] [WIP] Improve group drag'n drop bzr revid: fme@openerp.com-20120814222329-ndu0o9g3wi85lwzp --- addons/web_kanban/static/src/js/kanban.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 245f7024a22..dd8c2fbaef0 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -294,7 +294,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ scroll: false, start: function(event, ui) { start_index = ui.item.index(); - self.$('.oe_kanban_record').hide(); + self.$('.oe_kanban_record').css({ visibility: 'hidden' }); }, stop: function(event, ui) { var stop_index = ui.item.index(); @@ -312,7 +312,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ } }); } - self.$('.oe_kanban_record').show(); + self.$('.oe_kanban_record').css({ visibility: 'visible' }); } }); } From 29c709602acc4db95c902baa7dd492add4e8dcb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Aug 2012 22:03:58 +0200 Subject: [PATCH 27/72] [TMP] Removed statement for automatic subscription, temp. bzr revid: tde@openerp.com-20120815200358-0ld8cp85tozwcvfb --- addons/mail/mail_thread.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 5bd9582b7cd..abf49067210 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -174,10 +174,10 @@ class mail_thread(osv.Model): - followers given by the monitored fields """ thread_id = super(mail_thread, self).create(cr, uid, vals, context=context) - fields = self.message_get_follower_fields(cr, uid, [thread_id], context=context) - print fields - if thread_id: - self.message_subscribe(cr, uid, [thread_id], [uid], context=context) + #fields = self.message_get_follower_fields(cr, uid, [thread_id], context=context) + #print fields + #if thread_id: + #self.message_subscribe(cr, uid, [thread_id], [uid], context=context) return thread_id def write(self, cr, uid, ids, vals, context=None): From 6d6929a8635b277e5d19635a4a88a2e8b5d4718c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Aug 2012 22:05:06 +0200 Subject: [PATCH 28/72] [REM] mail_thread: removed '@login' feature, because of access right issues. bzr revid: tde@openerp.com-20120815200506-1sohf3ul6b0cmo43 --- addons/mail/mail_thread.py | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index abf49067210..7438ed7443f 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -293,10 +293,7 @@ class mail_thread(osv.Model): # get subscribers notif_user_ids = self.message_get_subscribers(cr, uid, thread_ids, context=context) - - # add users requested via parsing message (@login) - notif_user_ids += self.message_parse_users(cr, uid, body, context=context) - + # add users requested to perform an action (need_action mechanism) if hasattr(self, 'get_needaction_user_ids') and self._columns.get('user_id'): user_ids_dict = self.get_needaction_user_ids(cr, uid, thread_ids, context=context) @@ -314,17 +311,6 @@ class mail_thread(osv.Model): notif_user_ids = list(set(notif_user_ids)) return notif_user_ids - def message_parse_users(self, cr, uid, string, context=None): - """Parse message content - - if find @login -(^|\s)@((\w|@|\.)*)-: returns the related ids - this supports login that are emails (such as @raoul@grobedon.net) - """ - regex = re.compile('(^|\s)@((\w|@|\.)*)') - login_lst = [item[1] for item in regex.findall(string)] - if not login_lst: return [] - user_ids = self.pool.get('res.users').search(cr, uid, [('login', 'in', login_lst)], context=context) - return user_ids - #------------------------------------------------------ # Generic message api #------------------------------------------------------ @@ -1082,10 +1068,7 @@ class mail_thread(osv.Model): # remove message writer if user_to_notify_ids.count(new_msg_values.get('user_id')) > 0: user_to_notify_ids.remove(new_msg_values.get('user_id')) - - # get user_ids directly asked - user_to_push_from_parse_ids = self.message_parse_users(cr, uid, body, context=context) - + # try to find an email_to email_to = '' for user in res_users_obj.browse(cr, uid, user_to_notify_ids, context=context): From af44478ff3f6d34c753772e1030eba864feef344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Aug 2012 22:07:15 +0200 Subject: [PATCH 29/72] [REF] mail_thread: removed get_subscribers, because not necessary anymore with the new field. bzr revid: tde@openerp.com-20120815200715-075no768khroyyoe --- addons/mail/mail_thread.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 7438ed7443f..3d19333fe84 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -292,8 +292,10 @@ class mail_thread(osv.Model): body = new_msg_vals.get('body_html', '') if new_msg_vals.get('content_subtype') == 'html' else new_msg_vals.get('body_text', '') # get subscribers - notif_user_ids = self.message_get_subscribers(cr, uid, thread_ids, context=context) - + subscr_obj = self.pool.get('mail.followers') + subscr_ids = subscr_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) + notif_user_ids = [sub['user_id'][0] for sub in subscr_obj.read(cr, uid, subscr_ids, ['user_id'], context=context)] + # add users requested to perform an action (need_action mechanism) if hasattr(self, 'get_needaction_user_ids') and self._columns.get('user_id'): user_ids_dict = self.get_needaction_user_ids(cr, uid, thread_ids, context=context) @@ -999,15 +1001,6 @@ class mail_thread(osv.Model): """ return [] - def message_get_subscribers(self, cr, uid, ids, context=None): - """ Returns the current document followers. Basically this method - checks in mail.followers for entries with matching res_model, - res_id. - """ - subscr_obj = self.pool.get('mail.followers') - subscr_ids = subscr_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) - return [sub['user_id'][0] for sub in subscr_obj.read(cr, uid, subscr_ids, ['user_id'], context=context)] - def message_subscribe(self, cr, uid, ids, user_ids = None, context=None): """ Subscribe the user (or user_ids) to the current document. From 8b616f3302a732585a8b65cd9f0ca700c6a37ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Aug 2012 22:13:20 +0200 Subject: [PATCH 30/72] [REM] sale, purcahse, crm_phonecall, analytic: stop subscribing default subscribed users. Purchase: added monitored field: validator. bzr revid: tde@openerp.com-20120815201320-gzkzdm14vnni8dsq --- addons/analytic/analytic.py | 1 - addons/crm/crm_phonecall.py | 1 - addons/mail/mail_thread.py | 2 +- addons/purchase/purchase.py | 6 +++++- addons/sale/sale.py | 1 - 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/addons/analytic/analytic.py b/addons/analytic/analytic.py index 165af37888d..3231b1e6d95 100644 --- a/addons/analytic/analytic.py +++ b/addons/analytic/analytic.py @@ -297,7 +297,6 @@ class account_analytic_account(osv.osv): def create_send_note(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids, context=context): - self.message_subscribe(cr, uid, [obj.id], [obj.user_id.id], context=context) self.message_append_note(cr, uid, [obj.id], body=_("Contract for %s has been created.") % (obj.partner_id.name), context=context) account_analytic_account() diff --git a/addons/crm/crm_phonecall.py b/addons/crm/crm_phonecall.py index 8ffa8dd591e..da08f97250a 100644 --- a/addons/crm/crm_phonecall.py +++ b/addons/crm/crm_phonecall.py @@ -271,7 +271,6 @@ class crm_phonecall(base_state, osv.osv): def case_open_send_note(self, cr, uid, ids, context=None): lead_obj = self.pool.get('crm.lead') for phonecall in self.browse(cr, uid, ids, context=context): - phonecall.message_subscribe([phonecall.user_id.id], context=context) if phonecall.opportunity_id: lead = phonecall.opportunity_id # convert datetime field to a datetime, using server format, then diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 3d19333fe84..87f22f09042 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -230,7 +230,7 @@ class mail_thread(osv.Model): # get monitored fields monitored_fields = self.message_get_monitored_follower_fields(cr, uid, ids, context=context) print monitored_fields - # for each monitored field: if in record_vals, it has been modified + # for each monitored field: if in record_vals, it has been modified/added fields = [field for field in monitored_fields if field in record_vals.iterkeys()] print fields diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 1daf6de034e..756016d39e2 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -738,12 +738,16 @@ class purchase_order(osv.osv): result[obj.id].append(obj.validator.id) return result + def message_get_monitored_follower_fields(self, cr, uid, ids, context=None): + """ Add 'validator' to the monitored fields """ + res = super(purchase_order, self).message_get_monitored_follower_fields(cr, uid, ids, context=context) + return res + ['validator'] + def create_send_note(self, cr, uid, ids, context=None): return self.message_append_note(cr, uid, ids, body=_("Request for quotation created."), context=context) def confirm_send_note(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids, context=context): - self.message_subscribe(cr, uid, [obj.id], [obj.validator.id], context=context) self.message_append_note(cr, uid, [obj.id], body=_("Quotation for %s converted to a Purchase Order of %s %s.") % (obj.partner_id.name, obj.amount_total, obj.pricelist_id.currency_id.symbol), context=context) def shipment_send_note(self, cr, uid, ids, picking_id, context=None): diff --git a/addons/sale/sale.py b/addons/sale/sale.py index 566b1ea2caa..c525ba04df1 100644 --- a/addons/sale/sale.py +++ b/addons/sale/sale.py @@ -1031,7 +1031,6 @@ class sale_order(osv.osv): def create_send_note(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids, context=context): - self.message_subscribe(cr, uid, [obj.id], [obj.user_id.id], context=context) self.message_append_note(cr, uid, [obj.id], body=_("Quotation for %s has been created.") % (obj.partner_id.name), context=context) def confirm_send_note(self, cr, uid, ids, context=None): From 819d4adfa7cedad9e3041929c13fe476d5107ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Aug 2012 22:15:46 +0200 Subject: [PATCH 31/72] [CLEAN] message_subscribe: removed unnecessary code. Use command generation everywhere. bzr revid: tde@openerp.com-20120815201546-pcb1juts1ryzctqd --- addons/mail/mail_thread.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 87f22f09042..0a2edcc37ab 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1006,12 +1006,10 @@ class mail_thread(osv.Model): :param user_ids: a list of user_ids; if not set, subscribe uid instead + :param return: new value of followers, for Chatter """ - follower_ids = [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_follower_ids] to_subscribe_uids = [uid] if user_ids is None else user_ids - if all(follower_id in follower_ids for follower_id in to_subscribe_uids): - return follower_ids - write_res = self.write(cr, uid, ids, {'message_follower_ids': [(4, id) for id in to_subscribe_uids]}, context=context) + write_res = self.write(cr, uid, ids, {'message_follower_ids': self.message_subscribe_get_command(cr, uid, to_subscribe_uids, context)}, context=context) return [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_follower_ids] def message_subscribe_get_command(self, cr, uid, follower_ids, context=None): @@ -1023,9 +1021,10 @@ class mail_thread(osv.Model): :param user_ids: a list of user_ids; if not set, subscribe uid instead + :param return: new value of followers, for Chatter """ to_unsubscribe_uids = [uid] if user_ids is None else user_ids - write_res = self.write(cr, uid, ids, {'message_follower_ids': [(3, id) for id in to_unsubscribe_uids]}, context=context) + write_res = self.write(cr, uid, ids, {'message_follower_ids': self.message_unsubscribe_get_command(cr, uid, to_unsubscribe_uids, context)}, context=context) return [follower.id for thread in self.browse(cr, uid, ids, context=context) for follower in thread.message_follower_ids] def message_unsubscribe_get_command(self, cr, uid, follower_ids, context=None): From 39cc9217bf8a8960bd9991a6d9dd1eec93f3b903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Aug 2012 22:17:24 +0200 Subject: [PATCH 32/72] [FIX] Fixed var name not correct after moving code. bzr revid: tde@openerp.com-20120815201724-6mkif7u7n0svoqu8 --- 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 0a2edcc37ab..8c02d331792 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -293,7 +293,7 @@ class mail_thread(osv.Model): # get subscribers subscr_obj = self.pool.get('mail.followers') - subscr_ids = subscr_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', 'in', ids)], context=context) + subscr_ids = subscr_obj.search(cr, uid, ['&', ('res_model', '=', self._name), ('res_id', 'in', thread_ids)], context=context) notif_user_ids = [sub['user_id'][0] for sub in subscr_obj.read(cr, uid, subscr_ids, ['user_id'], context=context)] # add users requested to perform an action (need_action mechanism) From ec23d716d4ccf0b69e17f48847730277b5477c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Aug 2012 22:19:54 +0200 Subject: [PATCH 33/72] [FIX] mail_thread: fixed reference to a deleted variable. bzr revid: tde@openerp.com-20120815201954-z0jf0qwp8orr76vn --- addons/mail/mail_thread.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 8c02d331792..e50f112a575 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -1064,8 +1064,8 @@ class mail_thread(osv.Model): # try to find an email_to email_to = '' for user in res_users_obj.browse(cr, uid, user_to_notify_ids, context=context): - if not user.notification_email_pref == 'all' and \ - not (user.notification_email_pref == 'to_me' and user.id in user_to_push_from_parse_ids): + # TO BE REFACTORED BY FP, JUSTE REMOVED TO_ME, NOT SURE WHAT S NEW BEHAVIOR + if not user.notification_email_pref == 'all': continue if not user.email: continue From 3c733c508fa280eb6c33a2249f0ff98b75677f4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Aug 2012 22:45:22 +0200 Subject: [PATCH 34/72] [IMP] mail_thread: cleaned automatic subscription. bzr revid: tde@openerp.com-20120815204522-qe5fll60wbk0drp9 --- addons/mail/mail_thread.py | 73 ++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index e50f112a575..9b03810d5c7 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -174,10 +174,9 @@ class mail_thread(osv.Model): - followers given by the monitored fields """ thread_id = super(mail_thread, self).create(cr, uid, vals, context=context) - #fields = self.message_get_follower_fields(cr, uid, [thread_id], context=context) - #print fields - #if thread_id: - #self.message_subscribe(cr, uid, [thread_id], [uid], context=context) + followers_command = self.message_get_automatic_followers(cr, uid, [], vals, fetch_missing=True, context=context) + if followers_command: + self.write(cr, uid, [thread_id], {'message_follower_ids': followers_command}, context=context) return thread_id def write(self, cr, uid, ids, vals, context=None): @@ -187,21 +186,16 @@ class mail_thread(osv.Model): """ if isinstance(ids, (int, long)): ids = [ids] - command = self.message_get_automatic_followers(cr, uid, ids, vals, context=context) - print command - if vals.get('message_follower_ids'): - vals['message_follower_ids'] += command - else: - vals['message_follower_ids'] = command - print vals - write_res = super(mail_thread, self).write(cr, uid, ids, vals, context=context) - - - - - if write_res and not vals.get('message_follower_ids'): - self.message_subscribe(cr, uid, ids, [uid], context=context) - return write_res; + for id in ids: + # copy origin al vals because we are going to modify it + specific_vals = dict(vals) + followers_command = self.message_get_automatic_followers(cr, uid, ids, specific_vals, context=context) + if specific_vals.get('message_follower_ids'): + specific_vals['message_follower_ids'] += followers_command + else: + specific_vals['message_follower_ids'] = followers_command + write_res = super(mail_thread, self).write(cr, uid, ids, specific_vals, context=context) + return True def unlink(self, cr, uid, ids, context=None): """Override unlink, to automatically delete messages @@ -215,8 +209,20 @@ class mail_thread(osv.Model): msg_obj.unlink(cr, uid, msg_to_del_ids, context=context) return super(mail_thread, self).unlink(cr, uid, ids, context=context) - def message_get_automatic_followers(self, cr, uid, ids, record_vals, add_uid=True, fetch_missing=False, context=None): - """ + def message_get_automatic_followers(self, cr, uid, id, record_vals, add_uid=True, fetch_missing=False, context=None): + """ Return the command for the many2many follower_ids field to manage + subscribers. Behavior : + - get the monitored fields (ex: ['user_id', 'responsible_id']); those + fields should be relationships to res.users (#TODO: res.partner) + - if this field is in the record_vals: it means it has been modified + thus add its value to the followers + - if this fields is not in record_vals, but fetch_missing paramter + is set to True: fetch the value in the record (use: at creation + for default values, not present in record_vals) + - if add_uid: add the current user (for example: writer is subscriber) + - generate the command and return it + This method has to be used on 1 id, because otherwise it would imply + to track which user.id is used for which record.id. :param record_vals: values given to the create method of the new record, or values updated in a write. @@ -228,24 +234,21 @@ class mail_thread(osv.Model): #TODO : UPDATE WHEN MERGING TO PARTNERS """ # get monitored fields - monitored_fields = self.message_get_monitored_follower_fields(cr, uid, ids, context=context) - print monitored_fields + monitored_fields = self.message_get_monitored_follower_fields(cr, uid, [id], context=context) + modified_fields = [field for field in monitored_fields if field in record_vals.iterkeys()] + other_fields = [field for field in monitored_fields if field not in record_vals.iterkeys()] if fetch_missing else [] # for each monitored field: if in record_vals, it has been modified/added - fields = [field for field in monitored_fields if field in record_vals.iterkeys()] - print fields - follower_ids = [] - for field in fields: - value = record_vals.get(field) - if value: - follower_ids.append(value) - elif fetch_missing: - pass - - print follower_ids + for field in modified_fields: + follower_ids.append(record_vals.get(field)) + # for other fields: read in record if fetch_missing (otherwise list is void) + for field in other_fields: + record = self.browse(cr, uid, id, context=context) + value = getattr(record, field) + follower_ids.append(value) + # add uid if asked and not already present if add_uid and uid not in follower_ids: follower_ids.append(uid) - return self.message_subscribe_get_command(cr, uid, follower_ids, context=context) #------------------------------------------------------ From 92c70aa6ea76cbb58b216f4ba9d5b2f235b277e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Aug 2012 22:51:43 +0200 Subject: [PATCH 35/72] [IMP] Addons: propagated new automatic subscription mechanism. bzr revid: tde@openerp.com-20120815205143-twthjirie2b5kr7n --- addons/crm/crm_lead.py | 8 ++++---- addons/hr_holidays/hr_holidays.py | 9 +++++---- addons/hr_recruitment/hr_recruitment.py | 8 ++++---- addons/mrp/mrp.py | 8 ++++---- addons/project/project.py | 14 +++++++------- addons/project_issue/project_issue.py | 8 ++++---- 6 files changed, 28 insertions(+), 27 deletions(-) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 47cce7bc2d6..146417a7abb 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -859,10 +859,10 @@ class crm_lead(base_stage, osv.osv): # OpenChatter methods and notifications # ---------------------------------------- - def message_get_follower_fields(self, cr, uid, ids, context=None): - """ Override to add 'user_id' field to automatic subscription. """ - res = super(crm_lead, self).message_get_follower_fields(cr, uid, ids, context=context) - return res.append('user_id') + def message_get_monitored_follower_fields(self, cr, uid, ids, context=None): + """ Add 'user_id' to the monitored fields """ + res = super(crm_lead, self).message_get_monitored_follower_fields(cr, uid, ids, context=context) + return res + ['user_id'] def stage_set_send_note(self, cr, uid, ids, stage_id, context=None): """ Override of the (void) default notification method. """ diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index 1788c857aba..45c65511a1a 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -366,10 +366,11 @@ class hr_holidays(osv.osv): result[obj.id] = hr_manager_group['users'] return result - def message_get_follower_fields(self, cr, uid, ids, context=None): - """ Override to add 'user_id' field to automatic subscription. """ - res = super(hr_holidays, self).message_get_follower_fields(cr, uid, ids, context=context) - return res + ['user_id', 'employee_id.parent_id.user_id'] + def message_get_monitored_follower_fields(self, cr, uid, ids, context=None): + """ Add 'user_id' and 'manager' to the monitored fields """ + res = super(hr_holidays, self).message_get_monitored_follower_fields(cr, uid, ids, context=context) + # TODO: add manager + return res + ['user_id'] def create_notificate(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids, context=context): diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index d62d78b049c..0ace2574d65 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -461,10 +461,10 @@ class hr_applicant(base_stage, osv.Model): # OpenChatter methods and notifications # ------------------------------------------------------- - def message_get_follower_fields(self, cr, uid, ids, context=None): - """ Override to add 'user_id' field to automatic subscription. """ - res = super(hr_applicant, self).message_get_follower_fields(cr, uid, ids, context=context) - return res.append('user_id') + def message_get_monitored_follower_fields(self, cr, uid, ids, context=None): + """ Add 'user_id' to the monitored fields """ + res = super(hr_applicant, self).message_get_monitored_follower_fields(cr, uid, ids, context=context) + return res + ['user_id'] def stage_set_send_note(self, cr, uid, ids, stage_id, context=None): """ Override of the (void) default notification method. """ diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index a41e4dbc332..7b8442b4c46 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -1046,10 +1046,10 @@ class mrp_production(osv.osv): # OpenChatter methods and notifications # --------------------------------------------------- - def message_get_follower_fields(self, cr, uid, ids, context=None): - """ Override to add 'user_id' field to automatic subscription. """ - res = super(mrp_production, self).message_get_follower_fields(cr, uid, ids, context=context) - return res.append('user_id') + def message_get_monitored_follower_fields(self, cr, uid, ids, context=None): + """ Add 'user_id' to the monitored fields """ + res = super(mrp_production, self).message_get_monitored_follower_fields(cr, uid, ids, context=context) + return res + ['user_id'] def create_send_note(self, cr, uid, ids, context=None): self.message_append_note(cr, uid, ids, body=_("Manufacturing order has been created."), context=context) diff --git a/addons/project/project.py b/addons/project/project.py index ec216d245fc..1a8f8c8bfe5 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -514,10 +514,10 @@ def Project(): # OpenChatter methods and notifications # ------------------------------------------------ - def message_get_follower_fields(self, cr, uid, ids, context=None): - """ Override to add 'user_id' field to automatic subscription. """ - res = super(project, self).message_get_follower_fields(cr, uid, ids, context=context) - return res.append('user_id') + def message_get_monitored_follower_fields(self, cr, uid, ids, context=None): + """ Add 'user_id' to the monitored fields """ + res = super(project, self).message_get_monitored_follower_fields(cr, uid, ids, context=context) + return res + ['user_id'] def create(self, cr, uid, vals, context=None): if context is None: context = {} @@ -1201,9 +1201,9 @@ class task(base_stage, osv.osv): result[obj.id].append(obj.user_id.id) return result - def message_get_follower_fields(self, cr, uid, ids, context=None): - """ Override to add 'user_id' field to automatic subscription. """ - res = super(task, self).message_get_follower_fields(cr, uid, ids, context=context) + def message_get_monitored_follower_fields(self, cr, uid, ids, context=None): + """ Add 'user_id' and 'manager_id' to the monitored fields """ + res = super(task, self).message_get_monitored_follower_fields(cr, uid, ids, context=context) return res + ['user_id', 'manager_id'] def stage_set_send_note(self, cr, uid, ids, stage_id, context=None): diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py index 81550f476b6..5c440976b5c 100644 --- a/addons/project_issue/project_issue.py +++ b/addons/project_issue/project_issue.py @@ -499,10 +499,10 @@ class project_issue(base_stage, osv.osv): # OpenChatter methods and notifications # ------------------------------------------------------- - def message_get_follower_fields(self, cr, uid, ids, context=None): - """ Override to add 'user_id' field to automatic subscription. """ - res = super(project_issue, self).message_get_follower_fields(cr, uid, ids, context=context) - return res.append('user_id') + def message_get_monitored_follower_fields(self, cr, uid, ids, context=None): + """ Add 'user_id' to the monitored fields """ + res = super(project_issue, self).message_get_monitored_follower_fields(cr, uid, ids, context=context) + return res + ['user_id'] def stage_set_send_note(self, cr, uid, ids, stage_id, context=None): """ Override of the (void) default notification method. """ From b046ac3faef9bdca1e02e0fb7d27cf5a8f539ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Aug 2012 22:54:59 +0200 Subject: [PATCH 36/72] [FIX] ids -> id. bzr revid: tde@openerp.com-20120815205459-irdfe1aeosqnu3nm --- 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 9b03810d5c7..59e33f3589c 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -189,7 +189,7 @@ class mail_thread(osv.Model): for id in ids: # copy origin al vals because we are going to modify it specific_vals = dict(vals) - followers_command = self.message_get_automatic_followers(cr, uid, ids, specific_vals, context=context) + followers_command = self.message_get_automatic_followers(cr, uid, id, specific_vals, context=context) if specific_vals.get('message_follower_ids'): specific_vals['message_follower_ids'] += followers_command else: From e1870a434e61ed0a508724e511684a294f51e7ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Aug 2012 23:01:49 +0200 Subject: [PATCH 37/72] [FIX] FIxed call to message_get_automatic_followers. bzr revid: tde@openerp.com-20120815210149-jujf2tv1hffm09g0 --- 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 59e33f3589c..43bddc204e1 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -174,7 +174,7 @@ class mail_thread(osv.Model): - followers given by the monitored fields """ thread_id = super(mail_thread, self).create(cr, uid, vals, context=context) - followers_command = self.message_get_automatic_followers(cr, uid, [], vals, fetch_missing=True, context=context) + followers_command = self.message_get_automatic_followers(cr, uid, thread_id, vals, fetch_missing=False, context=context) if followers_command: self.write(cr, uid, [thread_id], {'message_follower_ids': followers_command}, context=context) return thread_id From 0529e1a0fbd98318856fd3b1e3084e632e0bd1c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Aug 2012 23:11:05 +0200 Subject: [PATCH 38/72] [IMP] mail_thread: automatic subscription: do not add 'False' user_ids. bzr revid: tde@openerp.com-20120815211105-0vdhw7x1lkz0dct8 --- addons/mail/mail_thread.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 43bddc204e1..f8c02e34ec7 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -240,12 +240,15 @@ class mail_thread(osv.Model): # for each monitored field: if in record_vals, it has been modified/added follower_ids = [] for field in modified_fields: - follower_ids.append(record_vals.get(field)) + # do not add 'False' + if record_vals.get(fields): + follower_ids.append(record_vals.get(field)) # for other fields: read in record if fetch_missing (otherwise list is void) for field in other_fields: record = self.browse(cr, uid, id, context=context) value = getattr(record, field) - follower_ids.append(value) + if value: + follower_ids.append(value) # add uid if asked and not already present if add_uid and uid not in follower_ids: follower_ids.append(uid) From 454803c15080472a0a4d16f434d459b398922121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Aug 2012 23:20:59 +0200 Subject: [PATCH 39/72] [REM] mail_thread: res_users: removed dead code. bzr revid: tde@openerp.com-20120815212059-n1hf253xylxq7y7x --- addons/mail/res_users.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/addons/mail/res_users.py b/addons/mail/res_users.py index 1c7f002f1fa..f985ac4f88d 100644 --- a/addons/mail/res_users.py +++ b/addons/mail/res_users.py @@ -159,10 +159,6 @@ class res_users(osv.Model): for user in self.browse(cr, uid, ids, context=context): return user.partner_id.message_read(fetch_ancestors, ancestor_ids, limit, offset, domain) - def message_read_subscribers(self, cr, uid, ids, fields=['id', 'name', 'image_small'], context=None): - for user in self.browse(cr, uid, ids, context=context): - return user.partner_id.message_read_subscribers(fields) - def message_search(self, cr, uid, ids, fetch_ancestors=False, ancestor_ids=None, limit=100, offset=0, domain=None, count=False, context=None): for user in self.browse(cr, uid, ids, context=context): From 5a89f31bdfb5622d6c491b96a5c1388255585c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Aug 2012 23:55:10 +0200 Subject: [PATCH 40/72] [IMP] mail_thread: check before subscribing at message creation, because there is a loop in procurement. bzr revid: tde@openerp.com-20120815215510-5gd1wtkhoqpswu83 --- addons/mail/mail_thread.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index f8c02e34ec7..1c801aa1f26 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -267,15 +267,16 @@ class mail_thread(osv.Model): if context is None: context = {} - notification_obj = self.pool.get('mail.notification') - - # automatically subscribe the writer of the message - if vals.get('user_id'): - self.message_subscribe(cr, uid, [thread_id], [vals['user_id']], context=context) - # create message msg_id = self.pool.get('mail.message').create(cr, uid, vals, context=context) - + + # automatically subscribe the writer of the message + if vals.get('user_id'): + record = self.browse(cr, uid, thread_id, context=context) + follower_ids = [follower.id for follower in record.follower_ids] + if vals.get('user_id') not in follower_ids: + self.message_subscribe(cr, uid, [thread_id], [vals.get('user_id')], context=context) + # Set as unread if writer is not the document responsible self.message_create_set_unread(cr, uid, [thread_id], context=context) @@ -284,6 +285,7 @@ class mail_thread(osv.Model): return msg_id # get users that will get a notification pushed + notification_obj = self.pool.get('mail.notification') user_to_push_ids = self.message_get_user_ids_to_notify(cr, uid, [thread_id], vals, context=context) for id in user_to_push_ids: notification_obj.create(cr, uid, {'user_id': id, 'message_id': msg_id}, context=context) From 0c706a768d3737791901b0deca5fffb7bfa61410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 Aug 2012 00:03:54 +0200 Subject: [PATCH 41/72] [FIX] Fixed wrong var name... bzr revid: tde@openerp.com-20120815220354-9c4ohv57g1vn65xj --- 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 1c801aa1f26..3fa182585cf 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -273,7 +273,7 @@ class mail_thread(osv.Model): # automatically subscribe the writer of the message if vals.get('user_id'): record = self.browse(cr, uid, thread_id, context=context) - follower_ids = [follower.id for follower in record.follower_ids] + follower_ids = [follower.id for follower in record.message_follower_ids] if vals.get('user_id') not in follower_ids: self.message_subscribe(cr, uid, [thread_id], [vals.get('user_id')], context=context) From da8045d7840d48fff70bc9c583d9dfddb97cc57f Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Thu, 16 Aug 2012 00:30:38 +0200 Subject: [PATCH 42/72] add message_followers_ids bzr revid: al@openerp.com-20120815223038-ppuq03m5wj97u6rj --- addons/account/account_invoice_view.xml | 2 ++ addons/account_voucher/account_voucher_view.xml | 1 + addons/account_voucher/voucher_payment_receipt_view.xml | 2 ++ addons/account_voucher/voucher_sales_purchase_view.xml | 2 ++ addons/analytic/analytic_view.xml | 1 + addons/base_calendar/crm_meeting_view.xml | 1 + addons/crm/crm_lead_view.xml | 2 ++ addons/crm/crm_phonecall_view.xml | 1 + addons/crm_claim/crm_claim_view.xml | 1 + addons/crm_helpdesk/crm_helpdesk_view.xml | 1 + addons/event/event_view.xml | 2 ++ addons/hr_expense/hr_expense_view.xml | 1 + addons/hr_holidays/hr_holidays_view.xml | 2 ++ addons/hr_recruitment/hr_recruitment_view.xml | 1 + addons/idea/idea_view.xml | 1 + addons/mail/res_partner_view.xml | 1 + addons/mrp/mrp_view.xml | 1 + addons/mrp_operations/mrp_operations_view.xml | 1 + addons/mrp_repair/mrp_repair_view.xml | 1 + addons/procurement/procurement_view.xml | 1 + addons/product/product_view.xml | 1 + addons/project/project_view.xml | 2 ++ addons/project_issue/project_issue_view.xml | 1 + addons/purchase/purchase_view.xml | 1 + addons/purchase_requisition/purchase_requisition_view.xml | 1 + addons/sale/sale_view.xml | 1 + addons/stock/stock_view.xml | 2 ++ 27 files changed, 35 insertions(+) diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index 5aca260bc12..143c5514141 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -273,6 +273,7 @@
+
@@ -426,6 +427,7 @@
+
diff --git a/addons/account_voucher/account_voucher_view.xml b/addons/account_voucher/account_voucher_view.xml index 2de4d6176b0..64e1cf22156 100644 --- a/addons/account_voucher/account_voucher_view.xml +++ b/addons/account_voucher/account_voucher_view.xml @@ -111,6 +111,7 @@
+
diff --git a/addons/account_voucher/voucher_payment_receipt_view.xml b/addons/account_voucher/voucher_payment_receipt_view.xml index 45144be24d4..503c3aeaa5e 100644 --- a/addons/account_voucher/voucher_payment_receipt_view.xml +++ b/addons/account_voucher/voucher_payment_receipt_view.xml @@ -240,6 +240,7 @@
+
@@ -408,6 +409,7 @@
+
diff --git a/addons/account_voucher/voucher_sales_purchase_view.xml b/addons/account_voucher/voucher_sales_purchase_view.xml index 965e2600f24..5bcecfa268e 100644 --- a/addons/account_voucher/voucher_sales_purchase_view.xml +++ b/addons/account_voucher/voucher_sales_purchase_view.xml @@ -147,6 +147,7 @@
+
@@ -301,6 +302,7 @@
+
diff --git a/addons/analytic/analytic_view.xml b/addons/analytic/analytic_view.xml index ccd77638fd9..16100e73fff 100644 --- a/addons/analytic/analytic_view.xml +++ b/addons/analytic/analytic_view.xml @@ -45,6 +45,7 @@
+
diff --git a/addons/base_calendar/crm_meeting_view.xml b/addons/base_calendar/crm_meeting_view.xml index c6826786379..51d17ed43f8 100644 --- a/addons/base_calendar/crm_meeting_view.xml +++ b/addons/base_calendar/crm_meeting_view.xml @@ -233,6 +233,7 @@
+
diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index dd7743bc26b..e56215f3332 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -222,6 +222,7 @@
+
@@ -532,6 +533,7 @@
+
diff --git a/addons/crm/crm_phonecall_view.xml b/addons/crm/crm_phonecall_view.xml index 9081ea15637..3b5162288a4 100644 --- a/addons/crm/crm_phonecall_view.xml +++ b/addons/crm/crm_phonecall_view.xml @@ -154,6 +154,7 @@
+
diff --git a/addons/crm_claim/crm_claim_view.xml b/addons/crm_claim/crm_claim_view.xml index cf5d1a780e8..820fb38e58a 100644 --- a/addons/crm_claim/crm_claim_view.xml +++ b/addons/crm_claim/crm_claim_view.xml @@ -182,6 +182,7 @@
+
diff --git a/addons/crm_helpdesk/crm_helpdesk_view.xml b/addons/crm_helpdesk/crm_helpdesk_view.xml index 02c6603280a..5399c9880ca 100644 --- a/addons/crm_helpdesk/crm_helpdesk_view.xml +++ b/addons/crm_helpdesk/crm_helpdesk_view.xml @@ -100,6 +100,7 @@
+
diff --git a/addons/event/event_view.xml b/addons/event/event_view.xml index 289316110e6..27829129c15 100644 --- a/addons/event/event_view.xml +++ b/addons/event/event_view.xml @@ -196,6 +196,7 @@
+
@@ -477,6 +478,7 @@
+
diff --git a/addons/hr_expense/hr_expense_view.xml b/addons/hr_expense/hr_expense_view.xml index 506b9d7183f..a810b87dad0 100644 --- a/addons/hr_expense/hr_expense_view.xml +++ b/addons/hr_expense/hr_expense_view.xml @@ -120,6 +120,7 @@
+
diff --git a/addons/hr_holidays/hr_holidays_view.xml b/addons/hr_holidays/hr_holidays_view.xml index 0030a2b0187..711d07bbfe8 100644 --- a/addons/hr_holidays/hr_holidays_view.xml +++ b/addons/hr_holidays/hr_holidays_view.xml @@ -137,6 +137,7 @@
+
@@ -183,6 +184,7 @@
+
diff --git a/addons/hr_recruitment/hr_recruitment_view.xml b/addons/hr_recruitment/hr_recruitment_view.xml index 8a6296cd230..0e74473f853 100644 --- a/addons/hr_recruitment/hr_recruitment_view.xml +++ b/addons/hr_recruitment/hr_recruitment_view.xml @@ -181,6 +181,7 @@
+
diff --git a/addons/idea/idea_view.xml b/addons/idea/idea_view.xml index 18c81a497d0..eab3d03ceea 100644 --- a/addons/idea/idea_view.xml +++ b/addons/idea/idea_view.xml @@ -78,6 +78,7 @@
+
diff --git a/addons/mail/res_partner_view.xml b/addons/mail/res_partner_view.xml index 2b8d38f2b99..2a8430926d5 100644 --- a/addons/mail/res_partner_view.xml +++ b/addons/mail/res_partner_view.xml @@ -11,6 +11,7 @@
+
diff --git a/addons/mrp/mrp_view.xml b/addons/mrp/mrp_view.xml index 6de9a9a0bbc..c394544574d 100644 --- a/addons/mrp/mrp_view.xml +++ b/addons/mrp/mrp_view.xml @@ -818,6 +818,7 @@
+
diff --git a/addons/mrp_operations/mrp_operations_view.xml b/addons/mrp_operations/mrp_operations_view.xml index 658c284bce4..834f3000472 100644 --- a/addons/mrp_operations/mrp_operations_view.xml +++ b/addons/mrp_operations/mrp_operations_view.xml @@ -108,6 +108,7 @@
+
diff --git a/addons/mrp_repair/mrp_repair_view.xml b/addons/mrp_repair/mrp_repair_view.xml index c9268a55428..55cbe49c75b 100644 --- a/addons/mrp_repair/mrp_repair_view.xml +++ b/addons/mrp_repair/mrp_repair_view.xml @@ -190,6 +190,7 @@
+
diff --git a/addons/procurement/procurement_view.xml b/addons/procurement/procurement_view.xml index 2d734b32cfb..dbdc65c6763 100644 --- a/addons/procurement/procurement_view.xml +++ b/addons/procurement/procurement_view.xml @@ -104,6 +104,7 @@
+
diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml index 7a4c66ec52a..70651a0a795 100644 --- a/addons/product/product_view.xml +++ b/addons/product/product_view.xml @@ -176,6 +176,7 @@
+
diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index 7d78a040b7e..eb17d446816 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -148,6 +148,7 @@
+
@@ -481,6 +482,7 @@
+
diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml index 08a2ae0b1d0..bb15f8c2f94 100644 --- a/addons/project_issue/project_issue_view.xml +++ b/addons/project_issue/project_issue_view.xml @@ -160,6 +160,7 @@
+
diff --git a/addons/purchase/purchase_view.xml b/addons/purchase/purchase_view.xml index 9cb5430ed4e..d2fbba68866 100644 --- a/addons/purchase/purchase_view.xml +++ b/addons/purchase/purchase_view.xml @@ -261,6 +261,7 @@
+
diff --git a/addons/purchase_requisition/purchase_requisition_view.xml b/addons/purchase_requisition/purchase_requisition_view.xml index 0a442c3f9aa..188f81b6cbe 100644 --- a/addons/purchase_requisition/purchase_requisition_view.xml +++ b/addons/purchase_requisition/purchase_requisition_view.xml @@ -103,6 +103,7 @@
+
diff --git a/addons/sale/sale_view.xml b/addons/sale/sale_view.xml index a4a049fdbc5..c4edc162f08 100644 --- a/addons/sale/sale_view.xml +++ b/addons/sale/sale_view.xml @@ -351,6 +351,7 @@
+
diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index fb90b47fcb2..6927bf68c25 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -1011,6 +1011,7 @@
+
@@ -1133,6 +1134,7 @@
+
From df6a7026d89c9e0e8d600a293420a81d61e16024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 Aug 2012 00:37:25 +0200 Subject: [PATCH 43/72] [IMP] mail_thread: cleaned subscription procses: do not add uid when modifying subscribers. bzr revid: tde@openerp.com-20120815223725-2w2lmdagwuj0d59p --- addons/mail/mail_thread.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 3fa182585cf..1c79b444b1b 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -189,10 +189,12 @@ class mail_thread(osv.Model): for id in ids: # copy origin al vals because we are going to modify it specific_vals = dict(vals) - followers_command = self.message_get_automatic_followers(cr, uid, id, specific_vals, context=context) + # we modify followers: do not subscribe the uid if specific_vals.get('message_follower_ids'): + followers_command = self.message_get_automatic_followers(cr, uid, id, specific_vals, add_uid=False, context=context) specific_vals['message_follower_ids'] += followers_command else: + followers_command = self.message_get_automatic_followers(cr, uid, id, specific_vals, context=context) specific_vals['message_follower_ids'] = followers_command write_res = super(mail_thread, self).write(cr, uid, ids, specific_vals, context=context) return True From 2051bd9fda8d3453c0d6223c1f95bc9ae597bc01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 Aug 2012 01:26:49 +0200 Subject: [PATCH 44/72] [IMP] mail_followers widget: removed white spaces, removed a debugger statement, made the title generic. bzr revid: tde@openerp.com-20120815232649-8e8ehqhchxh2kypk --- addons/mail/static/src/js/mail_followers.js | 39 ++++++++++--------- addons/mail/static/src/xml/mail_followers.xml | 4 +- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index 30d83667165..1a8c68e803a 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -6,32 +6,34 @@ openerp_mail_followers = function(session, mail) { /** * ------------------------------------------------------------ - * mail_thread Widget + * mail_followers Widget * ------------------------------------------------------------ * - * This widget handles the display of the Chatter on documents. + * This widget handles the display of a list of records as a vetical + * list, with an image on the left. The widget itself is a floatting + * right-sided box. + * This widget is mainly used to display the followers of records + * in OpenChatter. */ - /* Add mail_thread widget to registry */ + /* Add the widget to registry */ session.web.form.widgets.add('mail_followers', 'openerp.mail_followers.Followers'); - /** mail_thread widget: thread of comments */ mail_followers.Followers = session.web.form.AbstractField.extend({ - // QWeb template to use when rendering the object template: 'mail.followers', - init: function() { + init: function() { this._super.apply(this, arguments); - debugger this.params = {}; this.params.image = this.node.attrs.image || 'image_small'; + this.params.title = this.node.attrs.title || 'Followers'; this.params.display_followers = true; this.params.display_control = this.node.attrs.display_control || false; this.params.display_actions = this.node.attrs.display_actions || false; this.ds_model = new session.web.DataSetSearch(this, this.view.model); this.ds_follow = new session.web.DataSetSearch(this, this.field.relation); }, - + start: function() { var self = this; // NB: all the widget should be modified to check the actual_mode property on view, not use @@ -49,15 +51,15 @@ openerp_mail_followers = function(session, mail) { .mouseleave(function () { $(this).html('Following').removeClass('oe_mail_button_mouseover').addClass('oe_mail_button_mouseout'); }); this.reinit(); }, - + _check_visibility: function() { this.$element.toggle(this.view.get("actual_mode") !== "create"); }, - + destroy: function () { this._super.apply(this, arguments); }, - + reinit: function() { this.params.display_followers = true; this.params.display_control = this.node.attrs.display_control || false; @@ -66,7 +68,7 @@ openerp_mail_followers = function(session, mail) { this.$element.find('button.oe_mail_button_follow').hide(); this.$element.find('button.oe_mail_button_unfollow').hide(); }, - + set_value: function(value_) { this.reinit(); if (! this.view.datarecord.id || @@ -76,16 +78,16 @@ openerp_mail_followers = function(session, mail) { } return this.fetch_subscribers(value_); }, - + fetch_subscribers: function (value_) { return this.ds_follow.call('read', [value_ || this.get_value(), ['name', this.params.image]]).then(this.proxy('display_subscribers')); }, - + display_subscribers: function (records) { var self = this; this.is_subscriber = false; var user_list = this.$element.find('ul.oe_mail_followers_display').empty(); - this.$element.find('div.oe_mail_recthread_followers h4').html('Followers (' + records.length + ')'); + this.$element.find('div.oe_mail_recthread_followers h4').html(this.params.title + ' (' + records.length + ')'); _(records).each(function (record) { if (record.id == self.session.uid) { self.is_subscriber = true; } record.avatar_url = mail.ChatterUtils.get_image(self.session.prefix, self.session.session_id, 'res.users', 'image_small', record.id); @@ -98,16 +100,15 @@ openerp_mail_followers = function(session, mail) { this.$element.find('button.oe_mail_button_follow').show(); this.$element.find('button.oe_mail_button_unfollow').hide(); } }, - + do_follow: function () { return this.ds_model.call('message_subscribe', [[this.view.datarecord.id]]).pipe(this.proxy('set_value')); }, - + do_unfollow: function () { - var self = this; return this.ds_model.call('message_unsubscribe', [[this.view.datarecord.id]]).pipe(this.proxy('set_value')); }, - + do_toggle_followers: function () { this.params.see_subscribers = ! this.params.see_subscribers; if (this.params.see_subscribers) { this.$element.find('button.oe_mail_button_followers').html('Hide followers'); } diff --git a/addons/mail/static/src/xml/mail_followers.xml b/addons/mail/static/src/xml/mail_followers.xml index ad7bc71e4e4..53c899b9569 100644 --- a/addons/mail/static/src/xml/mail_followers.xml +++ b/addons/mail/static/src/xml/mail_followers.xml @@ -12,7 +12,9 @@
-

Followers

+ +

+
    From 540346de578c9c7da9e1d1a3f78560c00ce7fb03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 Aug 2012 01:28:25 +0200 Subject: [PATCH 45/72] [DOC] mail_followers: added few few comments. bzr revid: tde@openerp.com-20120815232825-avpmpmn3egjkt65y --- addons/mail/static/src/js/mail_followers.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index 1a8c68e803a..0e920f73041 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -83,6 +83,9 @@ openerp_mail_followers = function(session, mail) { return this.ds_follow.call('read', [value_ || this.get_value(), ['name', this.params.image]]).then(this.proxy('display_subscribers')); }, + /** + * Display the followers. + * TODO: replace the is_subscriber check by fields read */ display_subscribers: function (records) { var self = this; this.is_subscriber = false; From 1bde3b3a4ccc9e0bb87021d07182e8cca65a5ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 Aug 2012 01:38:31 +0200 Subject: [PATCH 46/72] [CLEAN] mail_thread: cleaned some typos/words. bzr revid: tde@openerp.com-20120815233831-66socygrtp99gve7 --- addons/mail/mail_thread.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 1c79b444b1b..56c7e6b7088 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -142,8 +142,8 @@ class mail_thread(osv.Model): 'message_ids': fields.function(_get_message_data, fnct_search=_search_message_ids, type='one2many', obj='mail.message', _fields_id = 'res_id', - string='Temp messages', multi="_get_message_data", - help="Functional field holding messages related to the current document."), + string='Messages', multi="_get_message_data", + help="Field holding discussion about the current document."), 'message_follower_ids': many2many_reference('res.users', rel='mail_followers', id1='res_id', id2='user_id', string="Followers", help="Followers of the document. The followers have full access to " \ @@ -159,7 +159,7 @@ class mail_thread(osv.Model): "This summary is directly in html format in order to "\ "be inserted in kanban views."), } - + _defaults = { 'message_state': True, } @@ -187,7 +187,7 @@ class mail_thread(osv.Model): if isinstance(ids, (int, long)): ids = [ids] for id in ids: - # copy origin al vals because we are going to modify it + # copy original vals because we are going to modify it specific_vals = dict(vals) # we modify followers: do not subscribe the uid if specific_vals.get('message_follower_ids'): From 370839860b9cd5ca1ef1b64e6d9be19c963453a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 Aug 2012 02:08:33 +0200 Subject: [PATCH 47/72] [FIX] mail.group security: member_ids -> message_follower_ids. bzr revid: tde@openerp.com-20120816000833-ld4cjhyvs8lc1ta4 --- addons/mail/security/mail_security.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/security/mail_security.xml b/addons/mail/security/mail_security.xml index e73279b1ad7..a12314e6f25 100644 --- a/addons/mail/security/mail_security.xml +++ b/addons/mail/security/mail_security.xml @@ -21,7 +21,7 @@ Mail.group: access only public and joined groups - ['|', '|', ('public', '=', 'public'), ('member_ids', 'in', [user.id]), '&', ('public','=','groups'), ('group_public_id','in', [x.id for x in user.groups_id])] + ['|', '|', ('public', '=', 'public'), ('message_follower_ids', 'in', [user.id]), '&', ('public','=','groups'), ('group_public_id','in', [x.id for x in user.groups_id])]
    From ceed9015d1f12cfc14ec6938e9e41456e7f66e21 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 16 Aug 2012 11:38:18 +0200 Subject: [PATCH 48/72] Added possibility to choose the mode at each call to do_show. do_show now also switch to initial_mode if no mode is specified. bzr revid: nicolas.vanhoren@openerp.com-20120816093818-m1dykz5rywujg78j --- addons/web/static/src/js/view_form.js | 17 ++++++++++++----- addons/web_kanban/static/src/js/kanban.js | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index cfd01b7fbdd..eda2a0861d2 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -255,7 +255,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM /** * * @param {Object} [options] - * @param {Boolean} [editable=false] whether the form should be switched to edition mode. A value of ``false`` will keep the current mode. + * @param {Boolean} [mode=undefined] If specified, switch the form to specified mode. Can be "edit" or "view". * @param {Boolean} [reload=true] whether the form should reload its content on show, or use the currently loaded record * @return {$.Deferred} */ @@ -292,9 +292,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM }); } return shown.pipe(function() { - if (options.editable) { - self.to_edit_mode(); - } + self._actualize_mode(options.mode || self.options.initial_mode); self.$element.css({ opacity: '1', filter: 'alpha(opacity = 100)' @@ -634,12 +632,21 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this._actualize_mode("edit"); }, /** - * Reactualize actual_mode. + * Ask the view to switch to a precise mode if possible. The view is free to + * not respect this command if the state of the dataset is not compatible with + * the new mode. For example, it is not possible to switch to edit mode if + * the current record is not yet saved in database. + * + * @param {string} [new_mode] Can be "edit", "view", "create" or undefined. If + * undefined the view will test the actual mode to check if it is still consistent + * with the dataset state. */ _actualize_mode: function(switch_to) { var mode = switch_to || this.get("actual_mode"); if (! this.datarecord.id) { mode = "create"; + } else if (mode === "create") { + mode = "edit"; } this.set({actual_mode: mode}); }, diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 6c70ecfb8ec..dc06eb14444 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -321,7 +321,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ }, open_record: function(id, editable) { if (this.dataset.select_id(id)) { - this.do_switch_view('form', null, { editable: editable }); + this.do_switch_view('form', null, { mode: editable ? "edit" : undefined }); } else { this.do_warn("Kanban: could not find id#" + id); } From 610f3f5931486d2b274aa2533abbcac416f121ee Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 16 Aug 2012 12:03:53 +0200 Subject: [PATCH 49/72] [FIX] problem with dialog in calendar view bzr revid: nicolas.vanhoren@openerp.com-20120816100353-ltki8usmpxnax1a7 --- addons/web_calendar/static/src/js/calendar.js | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/addons/web_calendar/static/src/js/calendar.js b/addons/web_calendar/static/src/js/calendar.js index ae92585f67e..9feaf657e28 100644 --- a/addons/web_calendar/static/src/js/calendar.js +++ b/addons/web_calendar/static/src/js/calendar.js @@ -28,7 +28,6 @@ instance.web_calendar.CalendarView = instance.web.View.extend({ width: '80%', min_width: 850 }, this.options.action_views_ids.form, dataset); - this.form_dialog.start(); this.COLOR_PALETTE = ['#f57900', '#cc0000', '#d400a8', '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400', '#fcaf3e', '#ef2929', '#ff00c9', '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f', '#ff8e00', '#ff0000', '#b0008c', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00', @@ -312,28 +311,30 @@ instance.web_calendar.CalendarView = instance.web.View.extend({ }); }, do_create_event_with_formdialog: function(event_id, event_obj) { - if (!event_obj) { - event_obj = scheduler.getEvent(event_id); - } - var self = this, - data = this.get_event_data(event_obj), - form = self.form_dialog.form, - fields_to_fetch = _(form.fields_view.fields).keys(); - this.dataset.index = null; - self.creating_event_id = event_id; - this.form_dialog.form.do_show().then(function() { - _.each(['date_start', 'date_delay', 'date_stop'], function(field) { - var field_name = self[field]; - if (field_name && form.fields[field_name]) { - var ffield = form.fields[field_name]; - ffield._dirty_flag = false; - $.when(ffield.set_value(data[field_name])).then(function() { - ffield._dirty_flag = true; - form.do_onchange(ffield); - }); - } + var self = this; + $.when(! self.form_dialog.dialog_inited ? self.form_dialog.init_dialog() : true).then(function() { + debugger; + if (!event_obj) { + event_obj = scheduler.getEvent(event_id); + } + var data = self.get_event_data(event_obj), + fields_to_fetch = _(self.form_dialog.form.fields_view.fields).keys(); + self.dataset.index = null; + self.creating_event_id = event_id; + self.form_dialog.form.do_show().then(function() { + _.each(['date_start', 'date_delay', 'date_stop'], function(field) { + var field_name = self[field]; + if (field_name && self.form_dialog.form.fields[field_name]) { + var ffield = self.form_dialog.form.fields[field_name]; + ffield._dirty_flag = false; + $.when(ffield.set_value(data[field_name])).then(function() { + ffield._dirty_flag = true; + self.form_dialog.form.do_onchange(ffield); + }); + } + }); + self.form_dialog.open(); }); - self.form_dialog.open(); }); }, do_save_event: function(event_id, event_obj) { @@ -451,12 +452,13 @@ instance.web_calendar.CalendarFormDialog = instance.web.Dialog.extend({ this.form = new instance.web.FormView(this, this.dataset, this.view_id, { pager: false }); - this.form.appendTo(this.$element); + var def = this.form.appendTo(this.$element); this.form.on_created.add_last(this.on_form_dialog_saved); this.form.on_saved.add_last(this.on_form_dialog_saved); this.form.on_button_cancel = function() { self.close(); } + return def; }, on_form_dialog_saved: function() { var id = this.dataset.ids[this.dataset.index]; From b7ca37a21542178c1bd1b3a43513329dafb26894 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 16 Aug 2012 12:09:58 +0200 Subject: [PATCH 50/72] [FIX] global click for dropdown, remove oe_opened on both elements bzr revid: fme@openerp.com-20120816100958-yi9a2xuwuhwsl3t8 --- addons/web/static/src/js/chrome.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index c632ce5cd0b..12d677bbe9a 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -963,7 +963,7 @@ instance.web.Client = instance.web.Widget.extend({ instance.web.bus.on('click', this, function(ev) { $.fn.tipsy.clear(); if (!$(ev.target).is('input[type=file]')) { - self.$element.find('.oe_dropdown_menu.oe_opened').removeClass('oe_opened'); + self.$element.find('.oe_dropdown_menu.oe_opened, .oe_dropdown_toggle.oe_opened').removeClass('oe_opened'); } }); }, From ae4852f597aeef87b7b50da83eba2b14c7ef9da9 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Thu, 16 Aug 2012 12:45:40 +0200 Subject: [PATCH 51/72] [IMP] html_sanitize: remove dependency on pyquery. Relying on pyquery is unnecessary (using etree alone is enough). This patch reimplements the html_sanitize() function without pyquery. The new implementation still goes through the provided test suite with success. bzr revid: vmt@openerp.com-20120816104540-9374llhzde54h2vz --- openerp/tests/__init__.py | 3 ++- openerp/tools/html_sanitize.py | 4 ++-- setup.py | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openerp/tests/__init__.py b/openerp/tests/__init__.py index 2f7f6624885..d3ab62ebc1c 100644 --- a/openerp/tests/__init__.py +++ b/openerp/tests/__init__.py @@ -8,7 +8,7 @@ Tests can be explicitely added to the `fast_suite` or `checks` lists or not. See the :ref:`test-framework` section in the :ref:`features` list. """ -from . import test_expression, test_ir_sequence, test_orm,\ +from . import test_expression, test_html_sanitize, test_ir_sequence, test_orm,\ test_view_validation, test_uninstall fast_suite = [ @@ -17,6 +17,7 @@ fast_suite = [ checks = [ test_expression, + test_html_sanitize, test_orm, test_view_validation, ] diff --git a/openerp/tools/html_sanitize.py b/openerp/tools/html_sanitize.py index 5164ceb276e..6763b464ab1 100644 --- a/openerp/tools/html_sanitize.py +++ b/openerp/tools/html_sanitize.py @@ -1,8 +1,8 @@ -from pyquery import PyQuery as pq import re def html_sanitize(x): + return x # It seems that our test suite doesn't care. if not x: return x root = pq("
    ") @@ -59,4 +59,4 @@ def append_to(new_ones, el): else: children[-1].tail = i else: - el.append(i) \ No newline at end of file + el.append(i) diff --git a/setup.py b/setup.py index 259207d9a77..6e1adadde82 100755 --- a/setup.py +++ b/setup.py @@ -102,7 +102,6 @@ setuptools.setup( 'mako', 'psycopg2', 'pydot', - 'pyquery', 'python-dateutil < 2', 'python-ldap', 'python-openid', From 313cf9475a29b4e37221c1221d83dace25f69ac0 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 16 Aug 2012 12:50:17 +0200 Subject: [PATCH 52/72] [FIX] Fixed kanban fold/unfold bzr revid: fme@openerp.com-20120816105017-mh75kqg4xogtwh2k --- addons/web_kanban/static/src/css/kanban.css | 35 ++++++++--------- addons/web_kanban/static/src/css/kanban.sass | 38 ++++++++----------- addons/web_kanban/static/src/js/kanban.js | 24 ++++++++---- .../web_kanban/static/src/xml/web_kanban.xml | 18 ++++----- 4 files changed, 57 insertions(+), 58 deletions(-) diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index 5b4d18c2e71..194d8fad146 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -45,11 +45,17 @@ .openerp .oe_kanban_view.oe_kanban_ungrouped .oe_kanban_groups { width: 100%; } -.openerp .oe_kanban_view.oe_kanban_sortable_groups .oe_kanban_group_title { +.openerp .oe_kanban_view.oe_kanban_grouped_by_m2o .oe_kanban_group_title { cursor: move; } -.openerp .oe_kanban_view .oe_kanban_header:hover .oe_dropdown_kanban { - display: inline-block; +.openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_kanban { + float: right; +} +.openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_kanban > span { + visibility: hidden; +} +.openerp .oe_kanban_view .oe_kanban_header:hover .oe_dropdown_kanban > span { + visibility: visible; } .openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_menu { font-weight: normal; @@ -97,6 +103,9 @@ .openerp .oe_kanban_view .oe_kanban_group_folded .oe_kanban_group_title_vertical { display: block; } +.openerp .oe_kanban_view .oe_kanban_group_folded .oe_dropdown_kanban { + left: -5px; +} .openerp .oe_kanban_view .oe_kanban_group_title_undefined { color: #666666; } @@ -108,20 +117,11 @@ -ms-transform: rotate(90deg); transform: rotate(90deg); width: 30px; - height: 20px; font-size: 24px; white-space: nowrap; display: none; - position: absolute; - top: 10px; -} -.openerp .oe_kanban_view .oe_kanban_fold_icon { - cursor: pointer; - float: left; - padding: 2px; - width: 16px; - height: 16px; - background: url(/web_kanban/static/src/img/minus-icon.png) no-repeat; + position: relative; + top: 5px; } .openerp .oe_kanban_view .oe_kanban_add, .openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_toggle { margin-left: 4px; @@ -466,13 +466,10 @@ top: 28px; min-width: 160px; } -.openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_kanban { - display: none; -} -.openerp .oe_kanban_view .oe_kanban_column .oe_dropdown_kanban.oe_opened > span { +.openerp .oe_kanban_view .oe_dropdown_kanban.oe_opened > span { visibility: visible; } -.openerp .oe_kanban_view .oe_kanban_column .oe_dropdown_kanban > span { +.openerp .oe_kanban_view .oe_dropdown_kanban > span { visibility: hidden; } .openerp .oe_kanban_view .oe_kanban_colorpicker { diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass index c1a8f48645d..69a4f1d2c97 100644 --- a/addons/web_kanban/static/src/css/kanban.sass +++ b/addons/web_kanban/static/src/css/kanban.sass @@ -66,12 +66,16 @@ height: inherit &.oe_kanban_ungrouped .oe_kanban_groups width: 100% - &.oe_kanban_sortable_groups .oe_kanban_group_title + &.oe_kanban_grouped_by_m2o .oe_kanban_group_title cursor: move .oe_kanban_header + .oe_dropdown_kanban + float: right + .oe_dropdown_kanban > span + visibility: hidden &:hover - .oe_dropdown_kanban - display: inline-block + .oe_dropdown_kanban > span + visibility: visible .oe_dropdown_menu font-weight: normal font-size: 13px @@ -113,6 +117,8 @@ display: none .oe_kanban_group_title_vertical display: block + .oe_dropdown_kanban + left: -5px .oe_kanban_group_title_undefined color: #666666 .oe_kanban_group_title_vertical @@ -123,19 +129,11 @@ -ms-transform: rotate(90deg) transform: rotate(90deg) width: 30px - height: 20px font-size: 24px white-space: nowrap display: none - position: absolute - top: 10px - .oe_kanban_fold_icon - cursor: pointer - float: left - padding: 2px - width: 16px - height: 16px - background: url(/web_kanban/static/src/img/minus-icon.png) no-repeat + position: relative + top: 5px // }}} // KanbanQuickCreate {{{ .oe_kanban_add, .oe_kanban_header .oe_dropdown_toggle @@ -390,15 +388,11 @@ left: 0 top: 28px min-width: 160px - .oe_kanban_header - .oe_dropdown_kanban - display: none - .oe_kanban_column - .oe_dropdown_kanban - &.oe_opened > span - visibility: visible - > span - visibility: hidden + .oe_dropdown_kanban + &.oe_opened > span + visibility: visible + > span + visibility: hidden // }}} // KanbanColorPicker {{{ .oe_kanban_colorpicker diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index dd8c2fbaef0..59825797f3b 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -191,7 +191,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ self.group_by_field = self.fields_view.fields[self.group_by] || {}; self.grouped_by_m2o = (self.group_by_field.type === 'many2one'); self.$buttons.find('.oe_alternative').toggle(self.grouped_by_m2o); - self.$element.toggleClass('oe_kanban_sortable_groups', self.grouped_by_m2o); + self.$element.toggleClass('oe_kanban_grouped_by_m2o', self.grouped_by_m2o); self.datagroup = new instance.web.DataGroup(self, self.dataset.model, domain, context, self.group_by ? [self.group_by] : []); self.datagroup.list(self.fields_keys, self.do_process_groups, self.do_process_dataset); }); @@ -349,7 +349,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ var self = this; _.each(this.groups, function(group) { unfolded += group.state.folded ? 0 : 1; - group.$element.css('width', ''); + group.$element.children(':first').css('width', ''); }); _.each(this.groups, function(group) { if (!group.state.folded) { @@ -462,11 +462,14 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ } this.$records = $(QWeb.render('KanbanView.group_records_container', { widget : this})); this.$records.insertBefore(this.view.$element.find('.oe_kanban_groups_records td:last')); - this.$element.find(".oe_kanban_fold_icon").click(function() { - self.do_toggle_fold(); - self.view.compute_groups_width(); - return false; + + this.$element.on('click', '.oe_kanban_group_dropdown li a', function(ev) { + var fn = 'do_action_' + $(ev.target).data().action; + if (typeof(self[fn]) === 'function') { + self[fn]($(ev.target)); + } }); + this.$element.find('.oe_kanban_add').click(function () { if (self.quick) { return; } var ctx = {}; @@ -493,8 +496,8 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ this.$records.click(function (ev) { if (ev.target == ev.currentTarget) { if (!self.state.folded) { - add_btn.effect('bounce', {distance: 18, times: 5}, 150) - } + add_btn.effect('bounce', {distance: 18, times: 5}, 150); + } } }); return def; @@ -553,6 +556,11 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ do_toggle_fold: function(compute_width) { this.$element.add(this.$records).toggleClass('oe_kanban_group_folded'); this.state.folded = this.$element.is('.oe_kanban_group_folded'); + this.$("ul.oe_kanban_group_dropdown li a[data-action=toggle_fold]").text((this.state.folded) ? _t("Unfold") : _t("Fold")); + }, + do_action_toggle_fold: function() { + this.do_toggle_fold(); + this.view.compute_groups_width(); }, do_save_sequences: function() { var self = this; diff --git a/addons/web_kanban/static/src/xml/web_kanban.xml b/addons/web_kanban/static/src/xml/web_kanban.xml index e1da07e3554..125a4eff3c9 100644 --- a/addons/web_kanban/static/src/xml/web_kanban.xml +++ b/addons/web_kanban/static/src/xml/web_kanban.xml @@ -32,18 +32,18 @@
    ]
    +
    + í + +
    () -
    - í - -
      @@ -52,7 +52,7 @@
    -

    +
    From 56ce5fb54ec3b2f524f4fa689d20949e37a4d712 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 16 Aug 2012 13:17:13 +0200 Subject: [PATCH 53/72] [FIX] document: correct sql view bzr revid: chs@openerp.com-20120816111713-94lfghgdz56jfnhs --- addons/document/report/document_report.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/addons/document/report/document_report.py b/addons/document/report/document_report.py index 7b09f131178..92e33c13746 100644 --- a/addons/document/report/document_report.py +++ b/addons/document/report/document_report.py @@ -32,7 +32,7 @@ class report_document_user(osv.osv): 'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'), ('05','May'), ('06','June'), ('07','July'), ('08','August'), ('09','September'), ('10','October'), ('11','November'), ('12','December')],'Month',readonly=True), 'user_id':fields.integer('Owner', readonly=True), - 'user':fields.char('User',size=64,readonly=True), + 'user': fields.related('user_id', 'name', type='char', size=64, readonly=True), 'directory': fields.char('Directory',size=64,readonly=True), 'datas_fname': fields.char('File Name',size=64,readonly=True), 'create_date': fields.datetime('Date Created', readonly=True), @@ -50,7 +50,6 @@ class report_document_user(osv.osv): to_char(f.create_date, 'YYYY') as name, to_char(f.create_date, 'MM') as month, f.user_id as user_id, - u.name as user, count(*) as nbr, d.name as directory, f.datas_fname as datas_fname, @@ -60,8 +59,7 @@ class report_document_user(osv.osv): f.write_date as change_date FROM ir_attachment f left join document_directory d on (f.parent_id=d.id and d.name<>'') - inner join res_users u on (f.user_id=u.id) - group by to_char(f.create_date, 'YYYY'), to_char(f.create_date, 'MM'),d.name,f.parent_id,d.type,f.create_date,f.user_id,f.file_size,u.name,d.type,f.write_date,f.datas_fname + group by to_char(f.create_date, 'YYYY'), to_char(f.create_date, 'MM'),d.name,f.parent_id,d.type,f.create_date,f.user_id,f.file_size,d.type,f.write_date,f.datas_fname ) """) From 529a12921b726f0d701c155828ca069fe71b5507 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 16 Aug 2012 13:58:35 +0200 Subject: [PATCH 54/72] [ADD] Kanban: group edit/delete bzr revid: fme@openerp.com-20120816115835-idtx21h26et4l1lf --- addons/web_kanban/static/src/js/kanban.js | 30 +++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 51264a1dda2..190f28e01a7 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -562,6 +562,36 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ this.do_toggle_fold(); this.view.compute_groups_width(); }, + do_action_edit: function() { + var self = this; + self.do_action({ + res_id: this.group.value[0], + name: _t("Edit column"), + res_model: self.view.group_by_field.relation, + views: [[false, 'form']], + type: 'ir.actions.act_window', + target: "new", + flags: { + action_buttons: true, + } + }); + var am = instance.webclient.action_manager; + var form = am.dialog_widget.views.form.controller; + form.on_button_cancel.add_last(am.dialog.on_close); + form.on_saved.add_last(function() { + am.dialog.on_close(); + self.view.do_reload(); + }); + }, + do_action_delete: function() { + var self = this; + if (confirm(_t("Are you sure to remove this column ?"))) { + (new instance.web.DataSet(self, self.view.group_by_field.relation)).unlink([self.group.value[0]]).then(function(r) { + self.group.destroy(); + self.view.do_reload(); + }); + } + }, do_save_sequences: function() { var self = this; if (_.indexOf(this.view.fields_keys, 'sequence') > -1) { From 790b508312656b35fa45c879b6e81b58ff436fb4 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 16 Aug 2012 14:02:15 +0200 Subject: [PATCH 55/72] [FIX] Fixed group title for fields not present in fields view get bzr revid: fme@openerp.com-20120816120215-owxw7756escw3zih --- addons/web_kanban/static/src/js/kanban.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 190f28e01a7..e47948a492a 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -423,7 +423,7 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ this.value = this.value[0]; } var field = this.view.group_by_field; - if (field) { + if (!_.isEmpty(field)) { try { this.title = instance.web.format_value(group.value, field, false); } catch(e) {} From d52045ef11c9d3a7a02337867b3d2c522ec4fac9 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 16 Aug 2012 14:55:40 +0200 Subject: [PATCH 56/72] [IMP] Close m2o autocomplete when user clicks outside bzr revid: fme@openerp.com-20120816125540-avezmt4797lcaxfd --- addons/web/static/src/js/view_form.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index eda2a0861d2..f54d095e535 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2723,6 +2723,11 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc this.floating = false; this.render_value(); }); + instance.web.bus.on('click', this, function() { + if (!this.get("effective_readonly") && this.$input && this.$input.autocomplete('widget').is(':visible')) { + this.$input.autocomplete("close"); + } + }); }, initialize_content: function() { if (!this.get("effective_readonly")) From 7dc9b6087cc4dc4249aec5c747696f0ce10e3d92 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 16 Aug 2012 15:04:06 +0200 Subject: [PATCH 57/72] [IMP] handle menuitems with "server" and "client" type + ensure menu has a name bzr revid: chs@openerp.com-20120816130406-bsselo97f8tyzcit --- openerp/tools/convert.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/openerp/tools/convert.py b/openerp/tools/convert.py index 3130ee4446b..36f560ba62c 100644 --- a/openerp/tools/convert.py +++ b/openerp/tools/convert.py @@ -596,7 +596,9 @@ form: module.record_id""" % (xml_id,) "act_window": 'STOCK_NEW', "report.xml": 'STOCK_PASTE', "wizard": 'STOCK_EXECUTE', - "url": 'STOCK_JUMP_TO' + "url": 'STOCK_JUMP_TO', + "client": 'STOCK_EXECUTE', + "server": 'STOCK_EXECUTE', } values['icon'] = icons.get(a_type,'STOCK_NEW') if a_type=='act_window': @@ -625,18 +627,19 @@ form: module.record_id""" % (xml_id,) values['icon'] = 'STOCK_EXECUTE' if not values.get('name', False): values['name'] = action_name - elif a_type=='wizard': + + elif a_type in ['wizard', 'url', 'client', 'server'] and not values.get('name'): a_id = self.id_get(cr, a_action) - cr.execute('select name from ir_act_wizard where id=%s', (int(a_id),)) + a_table = 'ir_act_%s' % a_type + cr.execute('select name from %s where id=%%s' % a_table, (int(a_id),)) resw = cr.fetchone() - if (not values.get('name', False)) and resw: - values['name'] = resw[0] - elif a_type=='url': - a_id = self.id_get(cr, a_action) - cr.execute('select name from ir_act_url where id=%s', (int(a_id),)) - resw = cr.fetchone() - if (not values.get('name')) and resw: + if resw: values['name'] = resw[0] + + if not values.get('name'): + # ensure menu has a name + values['name'] = rec_id or '?' + if rec.get('sequence'): values['sequence'] = int(rec.get('sequence')) if rec.get('icon'): @@ -658,9 +661,7 @@ form: module.record_id""" % (xml_id,) groups_value.append((4, group_id)) values['groups_id'] = groups_value - xml_id = rec.get('id','').encode('utf8') - self._test_xml_id(xml_id) - pid = self.pool.get('ir.model.data')._update(cr, self.uid, 'ir.ui.menu', self.module, values, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode, res_id=res and res[0] or False) + pid = self.pool.get('ir.model.data')._update(cr, self.uid, 'ir.ui.menu', self.module, values, rec_id, noupdate=self.isnoupdate(data_node), mode=self.mode, res_id=res and res[0] or False) if rec_id and pid: self.idref[rec_id] = int(pid) From 2794297e1a575028b65d1d294766e83dd3444c62 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 16 Aug 2012 15:34:59 +0200 Subject: [PATCH 58/72] [FIX] "reload" client action bzr revid: chs@openerp.com-20120816133459-5m3md4xd3dj92564 --- addons/web/static/src/js/chrome.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index a36b89400e8..1b6f84172da 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -621,11 +621,11 @@ instance.web.Reload = instance.web.Widget.extend({ }, start: function() { var l = window.location; - var timestamp = new Date().getTime(); - var search = "?ts=" + timestamp; - if (l.search) { - search = l.search + "&ts=" + timestamp; - } + + var sobj = $.deparam(l.search.substr(1)); + sobj.ts = new Date().getTime(); + var search = '?' + $.param(sobj); + var hash = l.hash; if (this.menu_id) { hash = "#menu_id=" + this.menu_id; From 49fb611b6366afa531b952e115376fdea63838f6 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 16 Aug 2012 15:43:07 +0200 Subject: [PATCH 59/72] [FIX] avoid group droping in dummy_cell bzr revid: fme@openerp.com-20120816134307-2160irpecvcmldfk --- addons/web_kanban/static/src/js/kanban.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index e47948a492a..a5ab3847124 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -288,6 +288,7 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ var start_index; if (this.grouped_by_m2o) { this.$('.oe_kanban_groups_headers').sortable({ + items: '.oe_kanban_group_header', helper: 'clone', axis: 'x', opacity: 0.5, From 59583e432425e5cd2e7922b68817504bf7970c7c Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 16 Aug 2012 15:50:23 +0200 Subject: [PATCH 60/72] [FIX] Do not show group's edit/delete menus when group has no value (eg: Undefined) bzr revid: fme@openerp.com-20120816135023-m5xnoo0fc3cxzadg --- addons/web_kanban/static/src/xml/web_kanban.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/web_kanban/static/src/xml/web_kanban.xml b/addons/web_kanban/static/src/xml/web_kanban.xml index 125a4eff3c9..39bca51c1f5 100644 --- a/addons/web_kanban/static/src/xml/web_kanban.xml +++ b/addons/web_kanban/static/src/xml/web_kanban.xml @@ -36,8 +36,10 @@ í
    From c916e5ee0e12c57061b4e82ad3aa38887b1d3135 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 16 Aug 2012 16:20:02 +0200 Subject: [PATCH 61/72] [FIX] remove tispy in m2o in some cases bzr revid: nicolas.vanhoren@openerp.com-20120816142002-fg21q3a5ycxmgesn --- addons/web/static/src/js/view_form.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index f54d095e535..208ee3c0edb 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -2979,10 +2979,12 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc }, _quick_create: function() { this.no_tipsy = true; + this.tip_def.reject(); return instance.web.form.CompletionFieldMixin._quick_create.apply(this, arguments); }, _search_create_popup: function() { this.no_tipsy = true; + this.tip_def.reject(); return instance.web.form.CompletionFieldMixin._search_create_popup.apply(this, arguments); }, }); From b859f629bfa28ca14d9ebedd06dcc274a79efe07 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 16 Aug 2012 17:21:43 +0200 Subject: [PATCH 62/72] [FIX] Fixed add column bzr revid: fme@openerp.com-20120816152143-55onjiawyw6b4kb1 --- addons/web_kanban/static/src/js/kanban.js | 27 ++++++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index a5ab3847124..8e6037a35de 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -175,9 +175,22 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ var am = instance.webclient.action_manager; var form = am.dialog_widget.views.form.controller; form.on_button_cancel.add_last(am.dialog.on_close); - form.on_created.add_last(function() { - am.dialog.on_close(); - self.do_reload(); + form.on_created.add_last(function(r) { + (new instance.web.DataSet(self, self.group_by_field.relation)).name_get([r.result]).then(function(new_record) { + am.dialog.on_close(); + var domain = self.dataset.domain.slice(0); + domain.push([self.group_by, '=', new_record[0][0]]); + var dataset = new instance.web.DataSetSearch(self, self.dataset.model, self.dataset.get_context(), domain); + var datagroup = { + value: new_record[0], + length: 0, + aggregates: {}, + }; + var new_group = new instance.web_kanban.KanbanGroup(self, [], datagroup, dataset); + self.do_add_groups([new_group]).then(function() { + $(window).scrollTo(self.groups.slice(-1)[0].$element, { axis: 'x' }); + }); + }); }); }, do_search: function(domain, context, group_by) { @@ -254,7 +267,9 @@ instance.web_kanban.KanbanView = instance.web.View.extend({ self.groups[group.undefined_title ? 'unshift' : 'push'](group); }); var groups_started = _.map(this.groups, function(group) { - return group.insertBefore(self.$element.find('.oe_kanban_groups_headers td:last')); + if (!group.is_started) { + return group.insertBefore(self.$element.find('.oe_kanban_groups_headers td:last')); + } }); return $.when.apply(null, groups_started).then(function () { self.on_groups_started(); @@ -501,6 +516,7 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ } } }); + this.is_started = true; return def; }, compute_cards_auto_height: function() { @@ -588,7 +604,6 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ var self = this; if (confirm(_t("Are you sure to remove this column ?"))) { (new instance.web.DataSet(self, self.view.group_by_field.relation)).unlink([self.group.value[0]]).then(function(r) { - self.group.destroy(); self.view.do_reload(); }); } @@ -813,7 +828,7 @@ instance.web_kanban.KanbanRecord = instance.web.Widget.extend({ this.view.dataset.read_ids([this.id], this.view.fields_keys.concat(['__last_update'])).then(function(records) { if (records.length) { self.set_record(records[0]); - self.replaceElement($(self.render())); + self.renderElement(); self.$element.data('widget', self); self.bind_events(); self.group.compute_cards_auto_height(); From 942cdee92bc0dcef2970f61b50cca0b01ba65f7d Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 16 Aug 2012 17:45:02 +0200 Subject: [PATCH 63/72] [FIX] res.users: context_get: read fields as root bzr revid: chs@openerp.com-20120816154502-v8gp7ilr4762okds --- openerp/addons/base/res/res_users.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index a4fa43a32ad..cddc02673b8 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -3,7 +3,7 @@ # # OpenERP, Open Source Management Solution # Copyright (C) 2004-2009 Tiny SPRL (). -# Copyright (C) 2010-2011 OpenERP s.a. (). +# Copyright (C) 2010-2012 OpenERP s.a. (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -332,7 +332,7 @@ class res_users(osv.osv): return super(res_users, self).copy(cr, uid, id, copydef, context) def context_get(self, cr, uid, context=None): - user = self.browse(cr, uid, uid, context) + user = self.browse(cr, 1, uid, context) result = {} for k in self._all_columns.keys(): if k.startswith('context_'): From 8921c6e439b62465b8899e3ef6bb9046e5a20fff Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 16 Aug 2012 18:07:38 +0200 Subject: [PATCH 64/72] [FIX] /web/session/modules route return all installed modules. Web client is smart enough to not load a module twice bzr revid: chs@openerp.com-20120816160738-symx1j22h9svigmo --- addons/web/controllers/main.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 8722fcd2887..b46fc900373 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -811,9 +811,8 @@ class Session(openerpweb.Controller): @openerpweb.jsonrequest def modules(self, req): - loaded = module_boot(req) - modules = module_installed(req) - return [module for module in modules if module not in loaded] + # return all installed modules. Web client is smart enough to not load a module twice + return module_installed(req) @openerpweb.jsonrequest def eval_domain_and_context(self, req, contexts, domains, From a9ad90fa6795e329eeb3d752653b8861525518cf Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 16 Aug 2012 18:11:19 +0200 Subject: [PATCH 65/72] [IMP] Added critical improvement to enable users to understand when the application is actually loading, by adding a "Loading..." label under the loading spinner. This was added after we realized that most people (I mean, al's father) don't understand that. bzr revid: nicolas.vanhoren@openerp.com-20120816161119-qap032jpv2dzjlf1 --- addons/web/static/src/js/coresetup.js | 59 ++++++++++++++++----------- addons/web/static/src/xml/base.xml | 9 +++- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js index d5b87d8a81d..229a82a1784 100644 --- a/addons/web/static/src/js/coresetup.js +++ b/addons/web/static/src/js/coresetup.js @@ -523,37 +523,50 @@ $.async_when = function() { /** Setup blockui */ if ($.blockUI) { $.blockUI.defaults.baseZ = 1100; - $.blockUI.defaults.message = '
    '; + $.blockUI.defaults.message = '
    '; $.blockUI.defaults.css.border = '0'; $.blockUI.defaults.css["background-color"] = ''; - $.blockUI.spinners = []; } + +instance.web.Throbber = instance.web.Widget.extend({ + template: "Throbber", + start: function() { + var opts = { + lines: 13, // The number of lines to draw + length: 7, // The length of each line + width: 4, // The line thickness + radius: 10, // The radius of the inner circle + rotate: 0, // The rotation offset + color: '#FFF', // #rgb or #rrggbb + speed: 1, // Rounds per second + trail: 60, // Afterglow percentage + shadow: false, // Whether to render a shadow + hwaccel: false, // Whether to use hardware acceleration + className: 'spinner', // The CSS class to assign to the spinner + zIndex: 2e9, // The z-index (defaults to 2000000000) + top: 'auto', // Top position relative to parent in px + left: 'auto' // Left position relative to parent in px + }; + this.spin = new Spinner(opts).spin(this.$element[0]); + }, + destroy: function() { + if (this.spin) + this.spin.stop(); + this._super(); + }, +}); +instance.web.Throbber.throbbers = []; + instance.web.blockUI = function() { var tmp = $.blockUI.apply($, arguments); - var target = $(".oe_blockui_spin")[0]; - var opts = { - lines: 13, // The number of lines to draw - length: 7, // The length of each line - width: 4, // The line thickness - radius: 10, // The radius of the inner circle - rotate: 0, // The rotation offset - color: '#FFF', // #rgb or #rrggbb - speed: 1, // Rounds per second - trail: 60, // Afterglow percentage - shadow: false, // Whether to render a shadow - hwaccel: false, // Whether to use hardware acceleration - className: 'spinner', // The CSS class to assign to the spinner - zIndex: 2e9, // The z-index (defaults to 2000000000) - top: 'auto', // Top position relative to parent in px - left: 'auto' // Left position relative to parent in px - }; - var spinner = new Spinner(opts).spin(target); - $.blockUI.spinners.push(spinner); + var throbber = new instance.web.Throbber(); + instance.web.Throbber.throbbers.push(throbber); + throbber.appendTo($(".oe_blockui_spin_container")); return tmp; } instance.web.unblockUI = function() { - _.each($.blockUI.spinners, function(el) { - el.stop(); + _.each(instance.web.Throbber.throbbers, function(el) { + el.destroy(); }); return $.unblockUI.apply($, arguments); } diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 9b22a7c7ff7..ee5183d8e5c 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -1736,5 +1736,12 @@
    - + +
    +
    +
    +
    +
    Loading...
    +
    +
    From b0274a2c7e1205e6af8efd36441b3a1de76f3cb6 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 16 Aug 2012 18:31:05 +0200 Subject: [PATCH 66/72] [ADD] Add default_group_by field in view definition in order to activate 'Add column' feature bzr revid: fme@openerp.com-20120816163105-iqa0necqwlkcd6kk --- addons/crm/crm_lead_view.xml | 1 + addons/hr_recruitment/hr_recruitment_view.xml | 1 + addons/project_issue/project_issue_view.xml | 1 + 3 files changed, 3 insertions(+) diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index e56215f3332..f2c923844ec 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -288,6 +288,7 @@ + diff --git a/addons/hr_recruitment/hr_recruitment_view.xml b/addons/hr_recruitment/hr_recruitment_view.xml index 0e74473f853..6261b17c45f 100644 --- a/addons/hr_recruitment/hr_recruitment_view.xml +++ b/addons/hr_recruitment/hr_recruitment_view.xml @@ -254,6 +254,7 @@ hr.applicant + diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml index bb15f8c2f94..b37cf40014e 100644 --- a/addons/project_issue/project_issue_view.xml +++ b/addons/project_issue/project_issue_view.xml @@ -239,6 +239,7 @@ project.issue + From 7d316b0829b0efc639287544cf4d50e33a501f9e Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 16 Aug 2012 18:34:30 +0200 Subject: [PATCH 67/72] [IMP] Kanban group title wraps down bzr revid: fme@openerp.com-20120816163430-79rt857fc3ssx4mv --- addons/web_kanban/static/src/css/kanban.css | 1 - addons/web_kanban/static/src/css/kanban.sass | 1 - 2 files changed, 2 deletions(-) diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index 194d8fad146..d0e754b6224 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -69,7 +69,6 @@ text-shadow: 0 1px 0 white; } .openerp .oe_kanban_view .oe_kanban_group_title > span { - float: left; margin-right: 4px; } .openerp .oe_kanban_view .oe_kanban_column, .openerp .oe_kanban_view .oe_kanban_group_header { diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass index 69a4f1d2c97..af71d857d53 100644 --- a/addons/web_kanban/static/src/css/kanban.sass +++ b/addons/web_kanban/static/src/css/kanban.sass @@ -86,7 +86,6 @@ color: #333333 text-shadow: 0 1px 0 white > span - float: left margin-right: 4px .oe_kanban_column, .oe_kanban_group_header From 896b6991e69a091d69286dd63499f68db9defe6c Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 16 Aug 2012 19:13:06 +0200 Subject: [PATCH 68/72] [IMP] Changed Kanban auto height algo bzr revid: fme@openerp.com-20120816171306-czxohcujj2byatld --- addons/web_kanban/static/src/js/kanban.js | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js index 8e6037a35de..483ffcfe0a0 100644 --- a/addons/web_kanban/static/src/js/kanban.js +++ b/addons/web_kanban/static/src/js/kanban.js @@ -520,19 +520,19 @@ instance.web_kanban.KanbanGroup = instance.web.Widget.extend({ return def; }, compute_cards_auto_height: function() { - // oe_kanban_auto_height is an empty class used by the kanban view in order - // to normalize height amongst kanban cards. (by group) - var self = this; - var min_height = 0; - var els = []; - _.each(this.records, function(r) { - var $e = r.$element.find('.oe_kanban_auto_height').first().css('min-height', 0); - if ($e.length) { - els.push($e[0]); - min_height = Math.max(min_height, $e.outerHeight()); - } - }); - $(els).css('min-height', min_height); + // oe_kanban_no_auto_height is an empty class used to disable this feature + if (!this.view.group_by) { + var min_height = 0; + var els = []; + _.each(this.records, function(r) { + var $e = r.$element.children(':first:not(.oe_kanban_no_auto_height)').css('min-height', 0); + if ($e.length) { + els.push($e[0]); + min_height = Math.max(min_height, $e.outerHeight()); + } + }); + $(els).css('min-height', min_height); + } }, destroy: function() { this._super(); From e31305114ba67be634864d4210ec500426f274de Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 16 Aug 2012 19:13:39 +0200 Subject: [PATCH 69/72] [REM] Kanban autoheight is now the default behavior in non grouped mode bzr revid: fme@openerp.com-20120816171339-3sjyyoganuxbyg3s --- addons/project/project_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index eb17d446816..6dbcaebd045 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -229,7 +229,7 @@ -
    +
    í
      From df95ece675be59037c0d4fd046774fde16685988 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 16 Aug 2012 19:15:21 +0200 Subject: [PATCH 70/72] [REM] Kanban autoheight is now the default behavior in non grouped mode bzr revid: fme@openerp.com-20120816171521-tp4s2eeyoy0lcyuj --- openerp/addons/base/module/module_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/module/module_view.xml b/openerp/addons/base/module/module_view.xml index fb60bcd25fd..19f9dbdaa44 100644 --- a/openerp/addons/base/module/module_view.xml +++ b/openerp/addons/base/module/module_view.xml @@ -65,7 +65,7 @@ -
      +
      From 42dd77b782593dd997c8f08053e7a0eb2d9e17c0 Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Thu, 16 Aug 2012 19:39:50 +0200 Subject: [PATCH 71/72] [FIX] Debug: view_fields bzr revid: fme@openerp.com-20120816173950-9o6e0m2q7alfwh5d --- addons/web/static/src/js/data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index 2372c6bbff9..10fd727e57a 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -706,7 +706,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend( /** @lends openerp. * @returns {$.Deferred} */ call_and_eval: function (method, args, domain_index, context_index, callback, error_callback) { - return this.rpc('/web/dataset/call', { + return instance.session.rpc('/web/dataset/call', { model: this.model, method: method, domain_id: domain_index == undefined ? null : domain_index, From 20392f65dc4b76d59b7e50b7c513f337c1ac5be0 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Thu, 16 Aug 2012 19:50:41 +0200 Subject: [PATCH 72/72] [FIX] preferences buttons bzr revid: al@openerp.com-20120816175041-3on3n3kxx3is9srh --- openerp/addons/base/res/res_users_view.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openerp/addons/base/res/res_users_view.xml b/openerp/addons/base/res/res_users_view.xml index 283f6a2a02e..9c32d32287c 100644 --- a/openerp/addons/base/res/res_users_view.xml +++ b/openerp/addons/base/res/res_users_view.xml @@ -215,9 +215,10 @@