diff --git a/addons/crm/crm.py b/addons/crm/crm.py index 27f50a0adb8..4c603777820 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -288,8 +288,7 @@ class crm_base(object): data = {'state': 'open', 'active': True} if not case.user_id: data['user_id'] = uid - self.write(cr, uid, case.id, data) - self._case_open_notification(case, context=context) + self.write(cr, uid, [case.id], data) self._action(cr, uid, cases, 'open') return True @@ -418,7 +417,7 @@ class crm_case(crm_base): data = {'state': 'open', 'active': True } if not case.user_id: data['user_id'] = uid - self.write(cr, uid, case.id, data) + self.write(cr, uid, [case.id], data) self._case_open_notification(case, context=context) self._action(cr, uid, cases, 'open') return True diff --git a/addons/crm_partner_assign/wizard/crm_forward_to_partner.py b/addons/crm_partner_assign/wizard/crm_forward_to_partner.py index 565f99b9db1..97d9ecac787 100644 --- a/addons/crm_partner_assign/wizard/crm_forward_to_partner.py +++ b/addons/crm_partner_assign/wizard/crm_forward_to_partner.py @@ -138,7 +138,7 @@ class crm_lead_forward_to_partner(osv.osv_memory): if email_to not in new_cc: new_cc.append(to) update_vals = {'email_cc' : ', '.join(new_cc) } - lead.write(cr, uid, case.id, update_vals, context=context) + lead.write(cr, uid, [case.id], update_vals, context=context) return res def _get_info_body_text(self, cr, uid, lead, context=None): diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index 78db0dc7063..f63dcf9632d 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -358,12 +358,16 @@ class hr_holidays(osv.osv): # OpenChatter and notifications # ----------------------------- + def message_get_subscribers(self, cr, uid, ids, context=None): + sub_ids = self._message_get_subscribers_ids(cr, uid, ids, context=context); + # add the employee and its manager if specified to the subscribed users + for obj in self.browse(cr, uid, ids, context=context): + if obj.employee_id.parent_id: + sub_ids.append(obj.employee_id.parent_id.user_id.id) + return self.pool.get('res.users').read(cr, uid, sub_ids, context=context) + def create_notificate(self, cr, uid, ids, context=None): for obj in self.browse(cr, uid, ids, context=context): - # add the employee and its manager if specified to the subscribed users - self.message_subscribe(cr, uid, ids, [obj.employee_id.user_id.id], context=context) - if obj.employee_id.parent_id: - self.message_subscribe(cr, uid, ids, [obj.employee_id.parent_id.user_id.id], context=context) self.message_append_note(cr, uid, ids, _('System notification'), _("The %s request '%s' has been created and is waiting confirmation") % ('leave' if obj.type == 'remove' else 'allocation', obj.name), type='notification', context=context) diff --git a/addons/hr_recruitment/wizard/hr_recruitment_create_partner_job.py b/addons/hr_recruitment/wizard/hr_recruitment_create_partner_job.py index dd1667aecef..ade9ce3deed 100644 --- a/addons/hr_recruitment/wizard/hr_recruitment_create_partner_job.py +++ b/addons/hr_recruitment/wizard/hr_recruitment_create_partner_job.py @@ -68,7 +68,7 @@ class hr_recruitment_partner_create(osv.osv_memory): 'email': case.email_from }, context=context) - case_obj.write(cr, uid, case.id, { + case_obj.write(cr, uid, [case.id], { 'partner_id': partner_id, 'partner_address_id': contact_id }, context=context) @@ -88,4 +88,4 @@ class hr_recruitment_partner_create(osv.osv_memory): hr_recruitment_partner_create() -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/mail/__openerp__.py b/addons/mail/__openerp__.py index f8e7c74e5f8..a644caea5e7 100644 --- a/addons/mail/__openerp__.py +++ b/addons/mail/__openerp__.py @@ -72,6 +72,7 @@ The main features are: 'images/customer_history.jpeg', 'images/messages_form.jpeg', 'images/messages_list.jpeg', + 'static/src/img/email_icong.png', ], 'css': [ 'static/src/css/mail.css', diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 1e8d3060313..85c297fb07f 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -68,6 +68,21 @@ class mail_thread(osv.osv): ), #widget='mail.ThreadView'), } + + #------------------------------------------------------ + # Automatic subscription when creating/reading + #------------------------------------------------------ + + def create(self, cr, uid, vals, context=None): + thread_id = super(mail_thread, self).create(cr, uid, vals, context=context); + self.message_subscribe(cr, uid, [thread_id], [uid], context=context) + return thread_id; + + def write(self, cr, uid, ids, vals, context=None): + write_res = super(mail_thread, self).write(cr, uid, ids, vals, context=context); + if write_res: + self.message_subscribe(cr, uid, ids, [uid], context=context) + return write_res; #------------------------------------------------------ # Generic message api @@ -597,21 +612,21 @@ class mail_thread(osv.osv): users = self.pool.get('res.users').read(cr, uid, user_ids, fields=['id', 'name', 'avatar_mini'], context=context) return users - def message_is_subscriber(self, cr, uid, ids, context=None): - # TODO: use message_get_subscribers ? as all subscriptions are in mail.subscription table, not necessary - subscription_obj = self.pool.get('mail.subscription') - sub_ids = subscription_obj.search(cr, uid, - ['&', '&', ('res_model', '=', self._name), ('res_id', 'in', ids), ('user_id', '=', uid)], context=context) - if len(sub_ids) > 1: - pass # TODO - return True if sub_ids else False + def message_is_subscriber(self, cr, uid, ids, user_id = None, context=None): + users = self.message_get_subscribers(cr, uid, ids, context=context) + sub_user_id = uid if user_id is None else user_id + if sub_user_id in [user['id'] for user in users]: + return True + return False def message_subscribe(self, cr, uid, ids, user_ids = None, context=None): subscription_obj = self.pool.get('mail.subscription') sub_user_ids = [uid] if user_ids is None else user_ids + create_ids = [] for id in ids: - create_ids = [subscription_obj.create(cr, uid, {'res_model': self._name, 'res_id': id, 'user_id': user_id}, context=context) - for user_id in sub_user_ids] + for user_id in sub_user_ids: + if self.message_is_subscriber(cr, uid, [id], user_id=user_id, context=context): continue + create_ids.append(subscription_obj.create(cr, uid, {'res_model': self._name, 'res_id': id, 'user_id': user_id}, context=context)) return create_ids def message_unsubscribe(self, cr, uid, ids, context=None): diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index d4eb2373b66..43c9c54afd0 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -20,6 +20,11 @@ margin-left: 5%; } +.oe_mail_wall_thread_content div.oe_mail_thread_act .oe_mail_action_textarea { + width: 100%; + height: 20px; + padding: 2px; +} /* Thread */ @@ -77,8 +82,26 @@ } .oe_mail_thread_msg, .oe_mail_thread_act { + width: 80%; white-space: normal; margin-bottom: 5px; + border-bottom: 1px solid #D2D9E7; +} + +.notification { + background: #E0E0E0; +} + +.email { + background: #E0E0E0; +} + +.oe_mail_thread_msg_more { + margin-left: 20%; + margin-right: 40%; + border: 1px solid #D2D9E7; + background: #E0E0E0; + text-align: center; } .oe_mail_thread_msg:after, .oe_mail_thread_act:after { @@ -92,15 +115,15 @@ } .oe_mail_action_textarea { - width: 60%; + width: 80%; height: 50px; padding: 5px; } .oe_mail_msg_image { float: left; - width: 60px; - height: 60px; + width: 45px; + height: 40px; text-align: center; overflow: hidden; -moz-border-radius: 3px; @@ -115,14 +138,13 @@ } .oe_mail_msg_image img { - width: 60px; + width: 40px; height: auto; clip: rect(10px, 100px, 110px, 0px); } .oe_mail_msg_content { - width: 89%; - margin-left: 11%; + margin-left: 50px; } .oe_mail_msg_p { @@ -130,10 +152,19 @@ margin: 0; } -.oe_mail_msg_body { +.oe_mail_msg_p_email_header { + border-bottom: 1px solid #D2D9E7; } -.oe_mail_msg_author, .oe_mail_msg_author a { +.oe_mail_msg_body a.reduce, .oe_mail_msg_body_short a.expand { + color: #4E43E7; +} + +.oe_mail_msg_author { + color: #747474; +} + +.oe_mail_msg_author a { color: #4E43E7; } @@ -141,6 +172,6 @@ color: #C03000; } -.oe_mail_msg_date, .oe_mail_msg_date a { - color: #4E43E7; +.oe_mail_msg_date { + color: #747474; } diff --git a/addons/mail/static/src/img/email_icon.png b/addons/mail/static/src/img/email_icon.png new file mode 100644 index 00000000000..6390d9e6e69 Binary files /dev/null and b/addons/mail/static/src/img/email_icon.png differ diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 84800358ada..d49b7a0768c 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -10,18 +10,30 @@ openerp.mail = function(session) { /* ThreadDisplay widget: display a thread of comments */ mail.ThreadDisplay = session.web.Widget.extend({ - // QWeb template to use when rendering the object template: 'ThreadDisplay', - + + /** + * + * @params {Object} parent parent + * @params {Object} [params] + * @param {String} [params.res_model] res_model of mail.thread object + * @param {Number} [params.res_id] res_id of record + * @param {Number} [params.uid] user id + * @param {Number} [params.char_show_more=100] number of character to display before adding a "show more" + * @param {Number} [params.limit=10] maximum number of messages to fetch + * @param {Number} [params.offset=0] offset for fetchign messages + * @param {Number} [params.records=null] records to show instead of fetching messages + */ init: function(parent, params) { this._super(parent); - this.res_model = params['res_model']; - this.res_id = params['res_id']; - this.uid = params['uid']; - this.records = params['records'] || false; - this.map_hash = {'res.users': []}; - /* DataSets */ - this.ds = new session.web.DataSet(this, this.res_model); + this.params = params; + this.params.limit = this.params.limit || 10; + this.params.offset = this.params.offset || 0; + this.params.records = this.params.records || null; + this.params.char_show_more = this.params.char_show_more || 100; + this.map_hash = {'res.users': {'login': [] }}; + /* define DataSets */ + this.ds = new session.web.DataSet(this, this.params.res_model); this.ds_users = new session.web.DataSet(this, 'res.users'); }, @@ -31,116 +43,147 @@ openerp.mail = function(session) { /* bind buttons */ this.$element.find('button.oe_mail_button_comment').bind('click', function () { self.do_comment(); }); /* delegate links */ - self.$element.find('div.oe_mail_thread_display').delegate('a', 'click', function (event) { - //console.log(event); - var res_model = event.srcElement.dataset.resModel; - var res_id = event.srcElement.dataset.resId; + self.$element.find('div.oe_mail_thread_display').delegate('a.intlink', 'click', function (event) { self.do_action({ type: 'ir.actions.act_window', - res_model: res_model, - res_id: parseInt(res_id), - //context: context, + res_model: event.srcElement.dataset.resModel, + res_id: parseInt(event.srcElement.dataset.resId), views: [[false, 'form']] }); }); /* display user, fetch comments */ this.display_current_user(); - if (this.records == false) this.fetch_comments(); - else this.display_comments(this.records); + if (this.params.records) return this.display_comments(this.params.records); + else return this.init_comments(); }, stop: function () { this._super.apply(this, arguments); }, - fetch_comments: function () { - var load_res = this.ds.call('message_load', [[this.res_id]]).then( + init_comments: function() { + var self = this; + this.params.offset = 0; + this.$element.find('div.oe_mail_thread_display').empty(); + return this.fetch_comments().then(function () { + self.$element.find('button.oe_mail_button_more').bind('click', function () { self.do_more(); }); + }); + }, + + fetch_comments: function (limit, offset) { + return this.ds.call('message_load', [[this.params.res_id], limit=(limit||this.params.limit), offset=(offset||this.params.offset)]).then( this.proxy('display_comments')); - return load_res; + }, + + display_comments: function (records) { + var self = this; + /* WIP: map matched regexp -> records to browse with name */ + //_(records).each(function (record) { + //self.do_check_internal_links(record.body_text); + //}); + _(records).each(function (record) { + if (record.type == 'email') { record.mini_url = ('/mail/static/src/img/email_icon.png'); } + else { record.mini_url = self.thread_get_avatar_mini('res.users', 'avatar_mini', record.user_id[0]); } + + // body text manipulation + record.body_text = self.do_clean_text(record.body_text); + record.tr_body_text = self.do_truncate_string(record.body_text, self.params.char_show_more); + record.body_text = self.do_replace_internal_links(record.body_text); + if (record.tr_body_text) record.tr_body_text = self.do_replace_internal_links(record.tr_body_text); + + // render + $(session.web.qweb.render('ThreadMsg', {'record': record})).appendTo(self.$element.find('div.oe_mail_thread_display')); + + // truncated: hide full-text, show summary, add buttons + if (record.tr_body_text) { + var node = self.$element.find('span.oe_mail_msg_body:last').append(' [ ... Show less]'); + self.$element.find('p.oe_mail_msg_p:last').append($('' + record.tr_body_text + ' [ ... Show more]')); + var new_node = self.$element.find('span.oe_mail_msg_body_short:last'); + node.hide(); + node.find('a:last').click(function() { node.hide(); new_node.show(); return false; }); + new_node.find('a:last').click(function() { new_node.hide(); node.show(); return false; }); + } + }); + // update offset for "More" buttons + this.params.offset += records.length; }, display_current_user: function () { $('
+ From:
+ To:
+
+