From 0fb391c4b5e371376432b3ff62e36320982f9106 Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Tue, 3 Feb 2015 13:41:41 +0200 Subject: [PATCH 01/77] [IMP] upload mail_move_message --- __init__.py | 1 + __openerp__.py | 20 ++++++ mail_move_message_models.py | 74 +++++++++++++++++++++++ mail_move_message_views.xml | 37 ++++++++++++ static/src/css/mail_move_message.css | 0 static/src/js/mail_move_message.js | 29 +++++++++ static/src/xml/mail_move_message_main.xml | 8 +++ 7 files changed, 169 insertions(+) create mode 100644 __init__.py create mode 100644 __openerp__.py create mode 100644 mail_move_message_models.py create mode 100644 mail_move_message_views.xml create mode 100644 static/src/css/mail_move_message.css create mode 100644 static/src/js/mail_move_message.js create mode 100644 static/src/xml/mail_move_message_main.xml diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..6cd8310 --- /dev/null +++ b/__init__.py @@ -0,0 +1 @@ +import mail_move_message_models diff --git a/__openerp__.py b/__openerp__.py new file mode 100644 index 0000000..37b943d --- /dev/null +++ b/__openerp__.py @@ -0,0 +1,20 @@ +{ + 'name' : 'Move message to thread', + 'version' : '1.0.0', + 'author' : 'Ivan Yelizariev', + 'category' : 'Custom', + 'website' : 'https://it-projects.info', + 'description': """ +Module allows move message to any thread. For example, customer send message to salesperson's alias. Then salesperson is able to move such private message to lead thread. + +Tested on Odoo 8.0 ab7b5d7732a7c222a0aea45bd173742acd47242d + """, + 'depends' : ['mail'], + 'data':[ + 'mail_move_message_views.xml', + ], + 'qweb': [ + 'static/src/xml/*.xml', + ], + 'installable': True +} diff --git a/mail_move_message_models.py b/mail_move_message_models.py new file mode 100644 index 0000000..240bbff --- /dev/null +++ b/mail_move_message_models.py @@ -0,0 +1,74 @@ +from openerp import api, models, fields, SUPERUSER_ID +from openerp.tools.translate import _ + +class wizard(models.TransientModel): + _name = 'mail_move_message.wizard' + + message_id = fields.Many2one('mail.message', string='Message') + message_body = fields.Html(related='message_id.body', string='Message to move', readonly=True) + parent_id = fields.Many2one('mail.message', string='Search by name') + model_id = fields.Many2one('ir.model', string='Record type') + res_id = fields.Integer('Record ID') + record_url = fields.Char('Link to record', readonly=True) + + @api.onchange('parent_id') + def on_change_parent_id(self): + if self.parent_id and self.parent_id.model: + self.model_id = self.env['ir.model'].search([('model', '=', self.parent_id.model)])[0] + self.res_id = self.parent_id.res_id + else: + self.model_id = None + self.res_id = None + + @api.onchange('model_id', 'res_id') + def on_change_res(self): + if not ( self.model_id and self.res_id ): + self.record_url = '' + return + + self.record_url = '/web#id=%s&model=%s' % (self.res_id, self.model_id.model) + + @api.multi + def move(self): + for r in self: + if r.parent_id: + if not (r.parent_id.model == r.model_id.model and + r.parent_id.res_id == r.res_id): + r.parent_id = None + + r.message_id.write({'parent_id': r.parent_id.id, 'res_id': r.res_id, 'model': r.model_id.model}) + if not ( r.model_id and r.res_id ): + obj = self.pool.get('ir.model.data').get_object_reference(self._cr, SUPERUSER_ID, 'mail', 'mail_archivesfeeds')[1] + return { + 'type' : 'ir.actions.client', + 'name' : 'Archive', + 'tag' : 'reload', + 'params' : {'menu_id': obj}, + } + return { + 'name': _('Record'), + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': r.model_id.model, + 'res_id': r.res_id, + 'views': [(False, 'form')], + 'type': 'ir.actions.act_window', + } + +class mail_message(models.Model): + _inherit = 'mail.message' + + def name_get(self, cr, uid, ids, context=None): + if not (context or {}).get('extended_name'): + return super(mail_message, self).name_get(cr, uid, ids, context=context) + if isinstance(ids, (list, tuple)) and not len(ids): + return [] + if isinstance(ids, (long, int)): + ids = [ids] + reads = self.read(cr, uid, ids, ['record_name','model', 'res_id'], context=context) + res = [] + for record in reads: + name = record['record_name'] + extended_name = ' [%s] ID %s' % (record.get('model', 'UNDEF'), record.get('res_id', 'UNDEF')) + res.append((record['id'], name + extended_name)) + return res diff --git a/mail_move_message_views.xml b/mail_move_message_views.xml new file mode 100644 index 0000000..bf2b782 --- /dev/null +++ b/mail_move_message_views.xml @@ -0,0 +1,37 @@ + + + + + + + mail_move_message.wizard.view + mail_move_message.wizard + +
+ + + + + + + +
+ +
+
+
+ +
+
+ +
+
+ diff --git a/static/src/css/mail_move_message.css b/static/src/css/mail_move_message.css new file mode 100644 index 0000000..e69de29 diff --git a/static/src/js/mail_move_message.js b/static/src/js/mail_move_message.js new file mode 100644 index 0000000..c44de1c --- /dev/null +++ b/static/src/js/mail_move_message.js @@ -0,0 +1,29 @@ +openerp.mail_move_message = function (session) { + var _t = session.web._t, + _lt = session.web._lt; + + var mail = session.mail; + + mail.ThreadMessage.include({ + bind_events: function(){ + this._super.apply(this, arguments); + this.$('.oe_move').on('click', this.on_move_message) + }, + on_move_message: function(event){ + var context = { + 'default_message_id': this.id + } + var action = { + type: 'ir.actions.act_window', + res_model: 'mail_move_message.wizard', + view_mode: 'form', + view_type: 'form', + views: [[false, 'form']], + target: 'new', + context: context, + }; + + this.do_action(action); + } + }) +} \ No newline at end of file diff --git a/static/src/xml/mail_move_message_main.xml b/static/src/xml/mail_move_message_main.xml new file mode 100644 index 0000000..4e15559 --- /dev/null +++ b/static/src/xml/mail_move_message_main.xml @@ -0,0 +1,8 @@ + + From c71d615c0f5ba0497e6c7aada649b36e5d03ae25 Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Tue, 3 Feb 2015 14:14:09 +0200 Subject: [PATCH 02/77] [IMP] check access and execute as superuser --- mail_move_message_models.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/mail_move_message_models.py b/mail_move_message_models.py index 240bbff..573ac58 100644 --- a/mail_move_message_models.py +++ b/mail_move_message_models.py @@ -28,15 +28,32 @@ class wizard(models.TransientModel): self.record_url = '/web#id=%s&model=%s' % (self.res_id, self.model_id.model) + @api.one + def check_access(self): + cr = self._cr + uid = self.env.user.id + operation = 'write' + context = self._context + + if not ( self.model_id and self.res_id ): + return True + model_obj = self.pool[self.model_id.model] + mids = model_obj.exists(cr, uid, [self.res_id]) + if hasattr(model_obj, 'check_mail_message_access'): + model_obj.check_mail_message_access(cr, uid, mids, operation, context=context) + else: + self.pool['mail.thread'].check_mail_message_access(cr, uid, mids, operation, model_obj=model_obj, context=context) + @api.multi def move(self): for r in self: + r.check_access() if r.parent_id: if not (r.parent_id.model == r.model_id.model and r.parent_id.res_id == r.res_id): r.parent_id = None - r.message_id.write({'parent_id': r.parent_id.id, 'res_id': r.res_id, 'model': r.model_id.model}) + r.message_id.sudo().write({'parent_id': r.parent_id.id, 'res_id': r.res_id, 'model': r.model_id.model}) if not ( r.model_id and r.res_id ): obj = self.pool.get('ir.model.data').get_object_reference(self._cr, SUPERUSER_ID, 'mail', 'mail_archivesfeeds')[1] return { From 2a320f9ec168895e96822cbc2fcf49ff41271647 Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Tue, 3 Feb 2015 15:08:35 +0200 Subject: [PATCH 03/77] [IMP] move also child messages --- mail_move_message_models.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/mail_move_message_models.py b/mail_move_message_models.py index 573ac58..2a1cccd 100644 --- a/mail_move_message_models.py +++ b/mail_move_message_models.py @@ -52,8 +52,16 @@ class wizard(models.TransientModel): if not (r.parent_id.model == r.model_id.model and r.parent_id.res_id == r.res_id): r.parent_id = None - - r.message_id.sudo().write({'parent_id': r.parent_id.id, 'res_id': r.res_id, 'model': r.model_id.model}) + ids = [r.message_id.id] + while True: + new_ids = self.env['mail.message'].search([('parent_id', 'in', ids), ('id', 'not in', ids)]).ids + if new_ids: + ids = ids + new_ids + continue + break + r.message_id.sudo().write({'parent_id': r.parent_id.id}) + self.env['mail.message'].sudo().search([('id', 'in', ids)]).write({'res_id': r.res_id, 'model': r.model_id.model}) + if not ( r.model_id and r.res_id ): obj = self.pool.get('ir.model.data').get_object_reference(self._cr, SUPERUSER_ID, 'mail', 'mail_archivesfeeds')[1] return { From 3f05622ec6ffef14a985f5c372808c8b37569aa6 Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Thu, 19 Feb 2015 19:36:02 +0200 Subject: [PATCH 04/77] new website https://yelizariev.github.io/ --- __openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__openerp__.py b/__openerp__.py index 37b943d..d49e5bd 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -3,7 +3,7 @@ 'version' : '1.0.0', 'author' : 'Ivan Yelizariev', 'category' : 'Custom', - 'website' : 'https://it-projects.info', + 'website' : 'https://yelizariev.github.io', 'description': """ Module allows move message to any thread. For example, customer send message to salesperson's alias. Then salesperson is able to move such private message to lead thread. From d163db7abef827d2bee9ecfcab49df75a6fa14c3 Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Sun, 22 Mar 2015 11:03:58 +0200 Subject: [PATCH 05/77] [FIX] check for null name --- mail_move_message_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mail_move_message_models.py b/mail_move_message_models.py index 2a1cccd..ec74bad 100644 --- a/mail_move_message_models.py +++ b/mail_move_message_models.py @@ -93,7 +93,7 @@ class mail_message(models.Model): reads = self.read(cr, uid, ids, ['record_name','model', 'res_id'], context=context) res = [] for record in reads: - name = record['record_name'] + name = record['record_name'] or '' extended_name = ' [%s] ID %s' % (record.get('model', 'UNDEF'), record.get('res_id', 'UNDEF')) res.append((record['id'], name + extended_name)) return res From 42447b91c1ec35b590d5e968759a46235579d56c Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Sun, 22 Mar 2015 11:36:44 +0200 Subject: [PATCH 06/77] [FIX] Message to move is not shown --- mail_move_message_views.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/mail_move_message_views.xml b/mail_move_message_views.xml index bf2b782..b74818b 100644 --- a/mail_move_message_views.xml +++ b/mail_move_message_views.xml @@ -21,6 +21,7 @@
+
From 2e2cdeccdbedd3e3888b448f2d252f949c0bdb76 Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Wed, 25 Mar 2015 01:45:01 +0200 Subject: [PATCH 07/77] [IMP] "move back" feature --- mail_move_message_models.py | 105 ++++++++++++++++++++++++++++++++---- mail_move_message_views.xml | 24 ++++++--- 2 files changed, 111 insertions(+), 18 deletions(-) diff --git a/mail_move_message_models.py b/mail_move_message_models.py index ec74bad..5e8f580 100644 --- a/mail_move_message_models.py +++ b/mail_move_message_models.py @@ -6,10 +6,36 @@ class wizard(models.TransientModel): message_id = fields.Many2one('mail.message', string='Message') message_body = fields.Html(related='message_id.body', string='Message to move', readonly=True) + message_moved_by_message_id = fields.Many2one('mail.message', related='message_id.moved_by_message_id', string='Moved with', readonly=True) + message_moved_by_user_id = fields.Many2one('res.users', related='message_id.moved_by_user_id', string='Moved by', readonly=True) parent_id = fields.Many2one('mail.message', string='Search by name') model_id = fields.Many2one('ir.model', string='Record type') res_id = fields.Integer('Record ID') record_url = fields.Char('Link to record', readonly=True) + can_move = fields.Boolean('Can move', compute='get_can_move') + move_back = fields.Boolean('Move to origin') + + @api.depends('message_id') + @api.one + def get_can_move(self): + # message was not moved before OR message is a top message of previous move + self.can_move = not self.message_id.moved_by_message_id or self.message_id.moved_by_message_id.id == self.message_id.id + + @api.onchange('move_back') + def on_change_move_back(self): + if not self.move_back: + return + self.parent_id = self.message_id.moved_from_parent_id + self.res_id = self.message_id.moved_from_res_id + model = self.message_id.moved_from_model + self.model_id = model and self.env['ir.model'].search([('model','=', model)]) + @api.onchange('parent_id', 'res_id', 'model_id') + def update_move_back(self): + model = self.message_id.moved_from_model + model_id = model and self.env['ir.model'].search([('model','=', model)]) + self.move_back = self.parent_id == self.message_id.moved_from_parent_id \ + and self.res_id == self.message_id.moved_from_res_id \ + and (self.model_id == model_id or (not self.model_id and not model_id)) @api.onchange('parent_id') def on_change_parent_id(self): @@ -45,6 +71,20 @@ class wizard(models.TransientModel): self.pool['mail.thread'].check_mail_message_access(cr, uid, mids, operation, model_obj=model_obj, context=context) @api.multi + def open_moved_by_message_id(self): + message_id = None + for r in self: + message_id = r.message_moved_by_message_id.id + return { + 'type': 'ir.actions.act_window', + 'res_model': 'mail_move_message.wizard', + 'view_mode': 'form', + 'view_type': 'form', + 'views': [[False, 'form']], + 'target': 'new', + 'context': {'default_message_id': message_id}, + } + @api.multi def move(self): for r in self: r.check_access() @@ -52,16 +92,8 @@ class wizard(models.TransientModel): if not (r.parent_id.model == r.model_id.model and r.parent_id.res_id == r.res_id): r.parent_id = None - ids = [r.message_id.id] - while True: - new_ids = self.env['mail.message'].search([('parent_id', 'in', ids), ('id', 'not in', ids)]).ids - if new_ids: - ids = ids + new_ids - continue - break - r.message_id.sudo().write({'parent_id': r.parent_id.id}) - self.env['mail.message'].sudo().search([('id', 'in', ids)]).write({'res_id': r.res_id, 'model': r.model_id.model}) - + r.message_id.move(r.parent_id.id, r.res_id, r.model_id.model, r.move_back) + if not ( r.model_id and r.res_id ): obj = self.pool.get('ir.model.data').get_object_reference(self._cr, SUPERUSER_ID, 'mail', 'mail_archivesfeeds')[1] return { @@ -83,6 +115,59 @@ class wizard(models.TransientModel): class mail_message(models.Model): _inherit = 'mail.message' + moved_from_res_id = fields.Integer('Related Document ID (Original)') + moved_from_model = fields.Char('Related Document Model (Original)') + moved_from_parent_id = fields.Many2one('mail.message', 'Parent Message (Original)', ondelete='set null') + moved_by_message_id = fields.Many2one('mail.message', 'Moved by message', ondelete='set null', help='Top message, that initate moving this message') + moved_by_user_id = fields.Many2one('res.users', 'Moved by user', ondelete='set null') + all_child_ids = fields.One2many('mail.message', string='All childs', compute='_get_all_childs', help='all childs, including subchilds') + + @api.one + def _get_all_childs(self, include_myself=True): + ids = [] + if include_myself: + ids.append(self.id) + while True: + new_ids = self.search([('parent_id', 'in', ids), ('id', 'not in', ids)]).ids + if new_ids: + ids = ids + new_ids + continue + break + self.all_child_ids = ids + + @api.one + def move(self, parent_id, res_id, model, move_back): + moved_by_message_id = self.id + moved_by_user_id = self.env.user.id + first_move = not self.moved_by_user_id + vals = {'parent_id': parent_id, + 'moved_by_user_id': moved_by_user_id} + if first_move: + # moved_from_* variables contain not last, but original + # reference + vals['moved_from_parent_id'] = self.parent_id.id + elif move_back: + # clear moved_from_* variabls if we move everything back + vals['moved_from_parent_id'] = None + + self.write(vals) + for r in self.all_child_ids: + vals = {'res_id': res_id, + 'model': model, + 'moved_by_user_id': moved_by_user_id, + 'moved_by_message_id': moved_by_message_id} + if move_back: + vals['moved_by_user_id'] = None + vals['moved_by_message_id'] = None + + if not r.moved_by_user_id or r.id == self.id and first_move: + vals['moved_from_res_id'] = r.res_id + vals['moved_from_model'] = r.model + elif move_back: + vals['moved_from_res_id'] = None + vals['moved_from_model'] = None + r.write(vals) + def name_get(self, cr, uid, ids, context=None): if not (context or {}).get('extended_name'): return super(mail_message, self).name_get(cr, uid, ids, context=context) diff --git a/mail_move_message_views.xml b/mail_move_message_views.xml index b74818b..6b04644 100644 --- a/mail_move_message_views.xml +++ b/mail_move_message_views.xml @@ -13,21 +13,29 @@ mail_move_message.wizard
- - - - + + +

You cannot move this message. It was already moved with a message bellow. Open one and apply changes there.

+ + + +
From 70a2210fc39a4b6b0744988d1540dd29f3b05421 Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Wed, 25 Mar 2015 11:58:29 +0200 Subject: [PATCH 08/77] [REF] bit cleanup code --- mail_move_message_models.py | 3 +-- mail_move_message_views.xml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mail_move_message_models.py b/mail_move_message_models.py index 5e8f580..fed3553 100644 --- a/mail_move_message_models.py +++ b/mail_move_message_models.py @@ -140,8 +140,7 @@ class mail_message(models.Model): moved_by_message_id = self.id moved_by_user_id = self.env.user.id first_move = not self.moved_by_user_id - vals = {'parent_id': parent_id, - 'moved_by_user_id': moved_by_user_id} + vals = {'parent_id': parent_id} if first_move: # moved_from_* variables contain not last, but original # reference diff --git a/mail_move_message_views.xml b/mail_move_message_views.xml index 6b04644..fd1076d 100644 --- a/mail_move_message_views.xml +++ b/mail_move_message_views.xml @@ -23,7 +23,7 @@ - + From ba40e5eed6dc7753bf39de3ac6edab2108fd5318 Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Wed, 25 Mar 2015 11:59:19 +0200 Subject: [PATCH 09/77] [FIX] untabify indent --- mail_move_message_views.xml | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/mail_move_message_views.xml b/mail_move_message_views.xml index fd1076d..c22436e 100644 --- a/mail_move_message_views.xml +++ b/mail_move_message_views.xml @@ -21,26 +21,25 @@