diff --git a/__init__.py b/__init__.py index 6cd8310..f247113 100644 --- a/__init__.py +++ b/__init__.py @@ -1 +1,2 @@ +import controllers import mail_move_message_models diff --git a/__openerp__.py b/__openerp__.py index 4f5a831..fe73ee5 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -1,15 +1,16 @@ { 'name' : 'Mail relocation', - 'version' : '1.0.1', + 'version' : '1.0.2', 'author' : 'IT-Projects LLC, Ivan Yelizariev', 'category' : 'Social Network', 'website' : 'https://yelizariev.github.io', 'price': 9.00, 'currency': 'EUR', - 'depends' : ['mail'], + 'depends' : ['mail', 'web_polymorphic_field'], 'images': ['images/inbox.png'], 'data':[ 'mail_move_message_views.xml', + 'data/mail_move_message_data.xml', ], 'qweb': [ 'static/src/xml/mail_move_message_main.xml', diff --git a/controllers/__init__.py b/controllers/__init__.py new file mode 100644 index 0000000..039d971 --- /dev/null +++ b/controllers/__init__.py @@ -0,0 +1 @@ +import main \ No newline at end of file diff --git a/controllers/main.py b/controllers/main.py new file mode 100644 index 0000000..bef9074 --- /dev/null +++ b/controllers/main.py @@ -0,0 +1,55 @@ +from openerp.addons.web.controllers.main import DataSet +from openerp.tools.translate import _ +from openerp import http +from openerp.http import request + +class DataSetCustom(DataSet): + + def _extend_name(self, model, records): + cr, uid, context = request.cr, request.uid, request.context + Model = request.registry[model] + fields = Model.fields_get(cr, uid, False, context) + contact_field = False + for n, f in fields.iteritems(): + if f['type'] == 'many2one' and f['relation'] == 'res.partner': + contact_field = n + break + partner_info = {} + if contact_field: + partner_info = Model.read(cr, uid, [r[0] for r in records], [contact_field], context) + partner_info = dict([(p['id'], p[contact_field]) for p in partner_info]) + res = [] + for r in records: + if partner_info.get(r[0]): + res.append((r[0], _('%s [%s] ID %s') % (r[1], partner_info.get(r[0])[1], r[0]))) + else: + res.append((r[0], _('%s ID %s') % (r[1], r[0]))) + return res + + + @http.route('/web/dataset/call_kw//name_search', type='json', auth="user") + def name_search(self, model, method, args, kwargs): + context = kwargs.get('context') + if context and context.get('extended_name_with_contact'): + #add order by ID desc + cr, uid = request.cr, request.uid + Model = request.registry[model] + search_args = list(kwargs.get('args') or []) + limit = int(kwargs.get('limit') or 100) + operator = kwargs.get('operator') + name = kwargs.get('name') + if Model._rec_name and (not name == '' and operator == 'ilike'): + search_args += [(Model._rec_name, operator, name)] + ids = Model.search(cr, uid, search_args, limit=limit, order='id desc', context=context) + res = Model.name_get(cr, uid, ids, context) + return self._extend_name(model, res) + + return self._call_kw(model, method, args, kwargs) + + @http.route('/web/dataset/call_kw//name_get', type='json', auth="user") + def name_get(self, model, method, args, kwargs): + res = self._call_kw(model, method, args, kwargs) + context = kwargs.get('context') + if context and context.get('extended_name_with_contact'): + res = self._extend_name(model, res) + return res diff --git a/data/mail_move_message_data.xml b/data/mail_move_message_data.xml new file mode 100644 index 0000000..2b13fe2 --- /dev/null +++ b/data/mail_move_message_data.xml @@ -0,0 +1,9 @@ + + + + + mail_relocation_models + crm.lead,project.task + + + \ No newline at end of file diff --git a/doc/changelog.rst b/doc/changelog.rst index 3720bd6..0f71071 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -3,6 +3,11 @@ Changelog ========= +`1.0.2` +------- + +- big improvements in interface + `1.0.1` ------- diff --git a/i18n/mail_move_message.pot b/i18n/mail_move_message.pot new file mode 100644 index 0000000..a8e8df2 --- /dev/null +++ b/i18n/mail_move_message.pot @@ -0,0 +1,168 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * mail_move_message +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-08-11 06:53+0000\n" +"PO-Revision-Date: 2015-08-11 06:53+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: mail_move_message +#: view:mail_move_message.wizard:mail_move_message.view_wizard +msgid "Cancel" +msgstr "" + +#. module: mail_move_message +#: field:mail_move_message.wizard,create_uid:0 +msgid "Created by" +msgstr "" + +#. module: mail_move_message +#: field:mail_move_message.wizard,create_date:0 +msgid "Created on" +msgstr "" + +#. module: mail_move_message +#: field:mail_move_message.wizard,id:0 +msgid "ID" +msgstr "" + +#. module: mail_move_message +#: field:mail.message,is_moved:0 +msgid "Is moved" +msgstr "" + +#. module: mail_move_message +#: field:mail_move_message.wizard,write_uid:0 +msgid "Last Updated by" +msgstr "" + +#. module: mail_move_message +#: field:mail_move_message.wizard,write_date:0 +msgid "Last Updated on" +msgstr "" + +#. module: mail_move_message +#: field:mail_move_message.wizard,record_url:0 +msgid "Link to record" +msgstr "" + +#. module: mail_move_message +#: model:ir.model,name:mail_move_message.model_mail_message +#: view:mail_move_message.wizard:mail_move_message.view_wizard +#: field:mail_move_message.wizard,message_id:0 +msgid "Message" +msgstr "" + +#. module: mail_move_message +#: view:mail_move_message.wizard:mail_move_message.view_wizard +msgid "Move" +msgstr "" + +#. module: mail_move_message +#: help:mail_move_message.wizard,move_back:0 +msgid "Move message and submessages to original place" +msgstr "" + +#. module: mail_move_message +#: view:mail_move_message.wizard:mail_move_message.view_wizard +msgid "Move Message" +msgstr "" + +#. module: mail_move_message +#: field:mail_move_message.wizard,move_back:0 +msgid "Move to origin" +msgstr "" + +#. module: mail_move_message +#. openerp-web +#: code:addons/mail_move_message/static/src/xml/mail_move_message_main.xml:5 +#, python-format +msgid "Move to thread" +msgstr "" + +#. module: mail_move_message +#: field:mail.message,moved_by_message_id:0 +msgid "Moved by message" +msgstr "" + +#. module: mail_move_message +#: field:mail.message,moved_by_user_id:0 +msgid "Moved by user" +msgstr "" + +#. module: mail_move_message +#: view:mail_move_message.wizard:mail_move_message.view_wizard +msgid "Open message" +msgstr "" + +#. module: mail_move_message +#: field:mail.message,moved_from_parent_id:0 +msgid "Parent Message (Original)" +msgstr "" + +#. module: mail_move_message +#: code:addons/mail_move_message/mail_move_message_models.py:107 +#, python-format +msgid "Record" +msgstr "" + +#. module: mail_move_message +#: field:mail_move_message.wizard,res_id:0 +msgid "Record ID" +msgstr "" + +#. module: mail_move_message +#: field:mail_move_message.wizard,model_id:0 +msgid "Record type" +msgstr "" + +#. module: mail_move_message +#: field:mail.message,moved_from_res_id:0 +msgid "Related Document ID (Original)" +msgstr "" + +#. module: mail_move_message +#: field:mail.message,moved_from_model:0 +msgid "Related Document Model (Original)" +msgstr "" + +#. module: mail_move_message +#. openerp-web +#: code:addons/mail_move_message/static/src/js/mail_move_message.js:17 +#, python-format +msgid "Relocate Message" +msgstr "" + +#. module: mail_move_message +#: field:mail_move_message.wizard,parent_id:0 +msgid "Search by name" +msgstr "" + +#. module: mail_move_message +#: help:mail.message,moved_by_message_id:0 +msgid "Top message, that initate moving this message" +msgstr "" + +#. module: mail_move_message +#: view:mail_move_message.wizard:mail_move_message.view_wizard +msgid "You cannot move this message. It was already moved with a message bellow. Open one and apply changes there." +msgstr "" + +#. module: mail_move_message +#: help:mail_move_message.wizard,model_id:0 +msgid "List available Models is configured at Settings\Technical\Emails\Mail Relocation. Empty for unassigned email" +msgstr "" + +#. module: mail_move_message +#: help:mail_move_message.wizard,filter_by_partner:0 +msgid "Show only records with the same partner as email author" +msgstr "" \ No newline at end of file diff --git a/i18n/sl.po b/i18n/sl.po new file mode 100644 index 0000000..971ffeb --- /dev/null +++ b/i18n/sl.po @@ -0,0 +1,160 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * mail_move_message +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-08-11 06:53+0000\n" +"PO-Revision-Date: 2015-08-11 08:58+0200\n" +"Last-Translator: Matjaz Mozetic \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: \n" +"Language: sl\n" +"X-Generator: Poedit 1.8.2\n" + +#. module: mail_move_message +#: view:mail_move_message.wizard:mail_move_message.view_wizard +msgid "Cancel" +msgstr "Preklic" + +#. module: mail_move_message +#: field:mail_move_message.wizard,create_uid:0 +msgid "Created by" +msgstr "Ustvaril" + +#. module: mail_move_message +#: field:mail_move_message.wizard,create_date:0 +msgid "Created on" +msgstr "Ustvarjeno" + +#. module: mail_move_message +#: field:mail_move_message.wizard,id:0 +msgid "ID" +msgstr "ID" + +#. module: mail_move_message +#: field:mail.message,is_moved:0 +msgid "Is moved" +msgstr "Je premaknjeno" + +#. module: mail_move_message +#: field:mail_move_message.wizard,write_uid:0 +msgid "Last Updated by" +msgstr "Zadnjič posodobil" + +#. module: mail_move_message +#: field:mail_move_message.wizard,write_date:0 +msgid "Last Updated on" +msgstr "Zadnjič posodobljeno" + +#. module: mail_move_message +#: field:mail_move_message.wizard,record_url:0 +msgid "Link to record" +msgstr "Povezava do zapisa" + +#. module: mail_move_message +#: model:ir.model,name:mail_move_message.model_mail_message +#: view:mail_move_message.wizard:mail_move_message.view_wizard +#: field:mail_move_message.wizard,message_id:0 +msgid "Message" +msgstr "Sporočilo" + +#. module: mail_move_message +#: view:mail_move_message.wizard:mail_move_message.view_wizard +msgid "Move" +msgstr "Premik" + +#. module: mail_move_message +#: help:mail_move_message.wizard,move_back:0 +msgid "Move message and submessages to original place" +msgstr "Premik sporočila in podrejenih sporočil na izvorno mesto" + +#. module: mail_move_message +#: view:mail_move_message.wizard:mail_move_message.view_wizard +msgid "Move Message" +msgstr "Premik sporočila" + +#. module: mail_move_message +#: field:mail_move_message.wizard,move_back:0 +msgid "Move to origin" +msgstr "Premik na izvor" + +#. module: mail_move_message +#. openerp-web +#: code:addons/mail_move_message/static/src/xml/mail_move_message_main.xml:5 +#, python-format +msgid "Move to thread" +msgstr "Premik v nit" + +#. module: mail_move_message +#: field:mail.message,moved_by_message_id:0 +msgid "Moved by message" +msgstr "Premaknjeno s sporočilom" + +#. module: mail_move_message +#: field:mail.message,moved_by_user_id:0 +msgid "Moved by user" +msgstr "Premaknil uporabnik" + +#. module: mail_move_message +#: view:mail_move_message.wizard:mail_move_message.view_wizard +msgid "Open message" +msgstr "Odpri sporočilo" + +#. module: mail_move_message +#: field:mail.message,moved_from_parent_id:0 +msgid "Parent Message (Original)" +msgstr "Nadrejeno sporočilo (original)" + +#. module: mail_move_message +#: code:addons/mail_move_message/mail_move_message_models.py:107 +#, python-format +msgid "Record" +msgstr "Zapis" + +#. module: mail_move_message +#: field:mail_move_message.wizard,res_id:0 +msgid "Record ID" +msgstr "ID zapisa" + +#. module: mail_move_message +#: field:mail_move_message.wizard,model_id:0 +msgid "Record type" +msgstr "Tip zapisa" + +#. module: mail_move_message +#: field:mail.message,moved_from_res_id:0 +msgid "Related Document ID (Original)" +msgstr "ID povezanega dokumenta (original)" + +#. module: mail_move_message +#: field:mail.message,moved_from_model:0 +msgid "Related Document Model (Original)" +msgstr "Model povezanega dokumenta (original)" + +#. module: mail_move_message +#. openerp-web +#: code:addons/mail_move_message/static/src/js/mail_move_message.js:17 +#, python-format +msgid "Relocate Message" +msgstr "Premik sporočila" + +#. module: mail_move_message +#: field:mail_move_message.wizard,parent_id:0 +msgid "Search by name" +msgstr "Iskanje po nazivu" + +#. module: mail_move_message +#: help:mail.message,moved_by_message_id:0 +msgid "Top message, that initate moving this message" +msgstr "Zgornje sporočilo, ki je sprožilo premik tega sporočila" + +#. module: mail_move_message +#: view:mail_move_message.wizard:mail_move_message.view_wizard +msgid "You cannot move this message. It was already moved with a message bellow. Open one and apply changes there." +msgstr "Tega sporočila ne morete premakniti, ker je bilo že premaknjeno s spodnjim sporočilom. Tam lahko uveljavljate spremembe." diff --git a/mail_move_message_models.py b/mail_move_message_models.py index 9455648..2f78936 100644 --- a/mail_move_message_models.py +++ b/mail_move_message_models.py @@ -1,20 +1,77 @@ +from lxml import etree from openerp import api, models, fields, SUPERUSER_ID +from openerp.tools import email_split from openerp.tools.translate import _ class wizard(models.TransientModel): _name = 'mail_move_message.wizard' + def _model_selection(self): + selection = [] + config_parameters = self.env['ir.config_parameter'] + model_names = config_parameters.get_param('mail_relocation_models') + model_names = model_names.split(',') if model_names else [] + + if 'default_message_id' in self.env.context: + message = self.env['mail.message'].browse(self.env.context['default_message_id']) + if message.model and message.model not in model_names: + model_names.append(message.model) + if message.moved_from_model and message.moved_from_model not in model_names: + model_names.append(message.moved_from_model) + if model_names: + selection = [(m.model, m.display_name) for m in self.env['ir.model'].search([('model', 'in', model_names)])] + + return selection + + @api.model + def default_get(self, fields_list): + res = super(wizard, self).default_get(fields_list) + + model_fields = self.fields_get() + if model_fields['model']['selection']: + res['model'] = model_fields['model']['selection'] and model_fields['model']['selection'][0][0] + + if 'message_id' in res: + message = self.env['mail.message'].browse(res['message_id']) + email_from = message.email_from + parts = email_split(email_from.replace(' ',',')) + if parts: + email = parts[0] + name = email_from[:email_from.index(email)].replace('"', '').replace('<', '').strip() or email_from + else: + name, email = email_from + res['message_name_from'] = name + res['message_email_from'] = email + + res['partner_id'] = message.author_id.id + if message.author_id and self.env.uid not in [u.id for u in message.author_id.user_ids]: + res['filter_by_partner'] = True + if message.author_id and res.get('model'): + res_id = self.env[res['model']].search([], order='id desc', limit=1) + res['res_id'] = res_id and res_id[0].id + + res['uid'] = self.env.uid + + return res + message_id = fields.Many2one('mail.message', string='Message') message_body = fields.Html(related='message_id.body', string='Message to move', readonly=True) + message_from = fields.Char(related='message_id.email_from', string='From', 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) message_is_moved = fields.Boolean(string='Is Moved', related='message_id.is_moved', 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) + parent_id = fields.Many2one('mail.message', string='Search by name', ) + model = fields.Selection(_model_selection, string='Model') + res_id = fields.Integer(string='Record') can_move = fields.Boolean('Can move', compute='get_can_move') - move_back = fields.Boolean('Move to origin', help='Move message and submessages to original place') + move_back = fields.Boolean('MOVE TO ORIGIN', help='Move message and submessages to original place') + partner_id = fields.Many2one('res.partner', string='Author') + filter_by_partner = fields.Boolean('Filter Records by partner') + message_email_from = fields.Char() + message_name_from = fields.Char() + # FIXME message_to_read should be True even if current message or any his childs are unread + message_to_read = fields.Boolean(related='message_id.to_read') + uid = fields.Integer() @api.depends('message_id') @api.one @@ -27,33 +84,45 @@ class wizard(models.TransientModel): 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') + if self.message_id.is_moved: + self.model = model + self.res_id = self.message_id.moved_from_res_id + + @api.onchange('parent_id', 'res_id', 'model') 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)) + and (self.model == model or (not self.model and not model)) @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.model = self.parent_id.model self.res_id = self.parent_id.res_id else: - self.model_id = None + self.model = 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.onchange('model', 'filter_by_partner', 'partner_id') + def on_change_partner(self): + domain = {'res_id': []} + if self.model and self.filter_by_partner and self.partner_id: + fields = self.env[self.model].fields_get(False) + contact_field = False + for n, f in fields.iteritems(): + if f['type'] == 'many2one' and f['relation'] == 'res.partner': + contact_field = n + break + if contact_field: + domain['res_id'] = [(contact_field, '=', self.partner_id.id)] + if self.model: + res_id = self.env[self.model].search(domain['res_id'], order='id desc', limit=1) + self.res_id = res_id and res_id[0].id + else: + self.res_id = None + return {'domain': domain} @api.one def check_access(self): @@ -62,9 +131,9 @@ class wizard(models.TransientModel): operation = 'write' context = self._context - if not ( self.model_id and self.res_id ): + if not ( self.model and self.res_id ): return True - model_obj = self.pool[self.model_id.model] + model_obj = self.pool[self.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) @@ -85,17 +154,20 @@ class wizard(models.TransientModel): 'target': 'new', 'context': {'default_message_id': message_id}, } + @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.move(r.parent_id.id, r.res_id, r.model_id.model, r.move_back) + if not r.parent_id or not (r.parent_id.model == r.model and + r.parent_id.res_id == r.res_id): + #link with the first message of record + parent = self.env['mail.message'].search([('model','=',r.model), ('res_id','=',r.res_id)], order='id', limit=1) + r.parent_id = parent.id or None - if not ( r.model_id and r.res_id ): + r.message_id.move(r.parent_id.id, r.res_id, r.model, r.move_back) + + if not ( r.model 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', @@ -107,12 +179,48 @@ class wizard(models.TransientModel): 'name': _('Record'), 'view_type': 'form', 'view_mode': 'form', - 'res_model': r.model_id.model, + 'res_model': r.model, 'res_id': r.res_id, 'views': [(False, 'form')], 'type': 'ir.actions.act_window', } + @api.one + def delete(self): + self.message_id.unlink() + return {} + + @api.model + def create_partner(self, message_id, relation, partner_id, message_name_from, message_email_from): + model = self.env[relation] + message = self.env['mail.message'].browse(message_id) + if not partner_id and message_name_from: + partner_id = self.env['res.partner'].with_context({'update_message_author': True}).create({ + 'name': message_name_from, + 'email': message_email_from + }).id + + context = {'partner_id': partner_id} + if model._rec_name: + context.update({'default_%s' % model._rec_name: message.subject}) + + fields = model.fields_get() + contact_field = False + for n, f in fields.iteritems(): + if f['type'] == 'many2one' and f['relation'] == 'res.partner': + contact_field = n + break + if contact_field: + context.update({'default_%s' % contact_field: partner_id}) + return context + + @api.one + def read_close(self): + self.message_id.set_message_read(True) + self.message_id.child_ids.set_message_read(True) + return {'type': 'ir.actions.act_window_close'} + + class mail_message(models.Model): _inherit = 'mail.message' @@ -193,3 +301,51 @@ class mail_message(models.Model): res = super(mail_message, self)._message_read_dict(cr, uid, message, parent_id, context) res['is_moved'] = message.is_moved return res + + +class mail_move_message_configuration(models.TransientModel): + _name = 'mail_move_message.config.settings' + _inherit = 'res.config.settings' + + model_ids = fields.Many2many(comodel_name='ir.model', string='Models') + + @api.model + def get_default_model_ids(self, fields): + config_parameters = self.env['ir.config_parameter'] + model_obj = self.env['ir.model'] + model_names = config_parameters.get_param('mail_relocation_models') + if not model_names: + return {} + model_names = model_names.split(',') + model_ids = model_obj.search([('model', 'in', model_names)]) + return {'model_ids': [m.id for m in model_ids]} + + @api.multi + def set_model_ids(self): + config_parameters = self.env['ir.config_parameter'] + model_names = '' + for record in self: + model_names = ','.join([m.model for m in record.model_ids]) + config_parameters.set_param('mail_relocation_models', model_names) + + +class res_partner(models.Model): + _inherit = 'res.partner' + + @api.model + def create(self, vals): + res = super(res_partner, self).create(vals) + if 'update_message_author' in self.env.context and 'email' in vals: + mail_message_obj = self.env['mail.message'] + # Escape special SQL characters in email_address to avoid invalid matches + email_address = (vals['email'].replace('\\', '\\\\').replace('%', '\\%').replace('_', '\\_')) + email_brackets = "<%s>" % email_address + messages = mail_message_obj.search([ + '|', + ('email_from', '=ilike', email_address), + ('email_from', 'ilike', email_brackets), + ('author_id', '=', False) + ]) + if messages: + messages.sudo().write({'author_id': res.id}) + return res diff --git a/mail_move_message_views.xml b/mail_move_message_views.xml index dd1e8f6..16b62d2 100644 --- a/mail_move_message_views.xml +++ b/mail_move_message_views.xml @@ -13,8 +13,13 @@ mail_move_message.wizard
+ + + + +

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

@@ -22,23 +27,88 @@