Browse Source

Merge branch '9.0' of /home/iii/addons-yelizariev/../mail_move_message into 9.0

pull/2/head
Ildar Nasyrov 9 years ago
parent
commit
401ee1674a
  1. 8
      mail_move_message/README.rst
  2. 2
      mail_move_message/__init__.py
  3. 20
      mail_move_message/__openerp__.py
  4. 1
      mail_move_message/controllers/__init__.py
  5. 55
      mail_move_message/controllers/main.py
  6. 9
      mail_move_message/data/mail_move_message_data.xml
  7. 26
      mail_move_message/doc/changelog.rst
  8. 173
      mail_move_message/i18n/mail_move_message.pot
  9. 160
      mail_move_message/i18n/sl.po
  10. BIN
      mail_move_message/images/inbox.png
  11. 382
      mail_move_message/mail_move_message_models.py
  12. 122
      mail_move_message/mail_move_message_views.xml
  13. BIN
      mail_move_message/static/description/delete-message.png
  14. BIN
      mail_move_message/static/description/html-message-viewer.png
  15. BIN
      mail_move_message/static/description/html-message-viewer1.png
  16. BIN
      mail_move_message/static/description/html-message.png
  17. BIN
      mail_move_message/static/description/icon.png
  18. BIN
      mail_move_message/static/description/inbox-move.png
  19. BIN
      mail_move_message/static/description/inbox.png
  20. 140
      mail_move_message/static/description/index.html
  21. BIN
      mail_move_message/static/description/record-move-back.png
  22. BIN
      mail_move_message/static/description/record1.png
  23. BIN
      mail_move_message/static/description/record2.png
  24. 13
      mail_move_message/static/src/css/mail_move_message.css
  25. 91
      mail_move_message/static/src/js/mail_move_message.js
  26. 8
      mail_move_message/static/src/xml/mail_move_message_main.xml

8
mail_move_message/README.rst

@ -0,0 +1,8 @@
Mail relocation
===============
Description: https://www.odoo.com/apps/modules/8.0/mail_move_message/
Further information and discussion: http://yelizariev.github.io/odoo/module/2015/04/10/mail-relocation.html
Tested on Odoo 8.0 d023c079ed86468436f25da613bf486a4a17d625

2
mail_move_message/__init__.py

@ -0,0 +1,2 @@
import controllers
import mail_move_message_models

20
mail_move_message/__openerp__.py

@ -0,0 +1,20 @@
{
'name' : 'Mail relocation',
'version' : '1.0.4',
'author' : 'IT-Projects LLC, Ivan Yelizariev',
'license': 'LGPL-3',
'category' : 'Social Network',
'website' : 'https://twitter.com/yelizariev',
'price': 9.00,
'currency': 'EUR',
'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',
],
'installable': False
}

1
mail_move_message/controllers/__init__.py

@ -0,0 +1 @@
import main

55
mail_move_message/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/<model>/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/<model>/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

9
mail_move_message/data/mail_move_message_data.xml

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<openerp>
<data noupdate="1">
<record id="mail_relocation_models" model="ir.config_parameter">
<field name="key">mail_relocation_models</field>
<field name="value">crm.lead,project.task</field>
</record>
</data>
</openerp>

26
mail_move_message/doc/changelog.rst

@ -0,0 +1,26 @@
.. _changelog:
Changelog
=========
`1.0.4`
-------
- FIX: don't allow to relocate message to itself as it cause infinitive loop
- ADD: 'Move Followers' option -- Add followers of current record to a new record.
`1.0.3`
-------
- FIX email_from parsing. There was an error with specific email_from value (e.g. '"name @ example" <name@example.com>')
`1.0.2`
-------
- big improvements in interface
`1.0.1`
-------
- fix bug "some messages are not shown in inbox after relocation"
- improve "Move back" tool

173
mail_move_message/i18n/mail_move_message.pot

@ -0,0 +1,173 @@
# 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 ""
#. module: mail_move_message
#: help:mail_move_message.wizard,move_followers:0
msgid "Add followers of current record to a new record.\nYou must use this option, if new record has restricted access.\nYou can change default value for this option at Settings/System Parameters"
msgstr ""

160
mail_move_message/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 <m.mozetic@matmoz.si>\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."

BIN
mail_move_message/images/inbox.png

After

Width: 861  |  Height: 628  |  Size: 128 KiB

382
mail_move_message/mail_move_message_models.py

@ -0,0 +1,382 @@
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.find(email) != -1 and 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
config_parameters = self.env['ir.config_parameter']
res['move_followers'] = config_parameters.get_param('mail_relocation_move_followers')
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_subject = fields.Char(related='message_id.subject', string='Subject', 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 = 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')
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()
move_followers = fields.Boolean(
'Move Followers',
help="Add followers of current record to a new record.\n"
"You must use this option, if new record has restricted access.\n"
"You can change default value for this option at Settings/System Parameters")
@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
model = self.message_id.moved_from_model
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
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 == 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 = self.parent_id.model
self.res_id = self.parent_id.res_id
else:
self.model = None
self.res_id = None
@api.onchange('model', 'filter_by_partner', 'partner_id')
def on_change_partner(self):
domain = {'res_id': [('id', '!=', self.message_id.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'].append((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):
cr = self._cr
uid = self.env.user.id
operation = 'write'
context = self._context
if not ( self.model and self.res_id ):
return True
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)
else:
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()
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
r.message_id.move(r.parent_id.id, r.res_id, r.model, r.move_back, r.move_followers)
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',
'name' : 'Archive',
'tag' : 'reload',
'params' : {'menu_id': obj},
}
return {
'name': _('Record'),
'view_type': 'form',
'view_mode': 'form',
'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'
is_moved = fields.Boolean('Is moved')
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
moved_childs = self.search([('moved_by_message_id', '=', self.id)]).ids
self.all_child_ids = ids + moved_childs
@api.multi
def move_followers(self, model, ids):
fol_obj = self.env['mail.followers']
for message in self:
followers = fol_obj.sudo().search([('res_model', '=', message.model),
('res_id', '=', message.res_id)])
for f in followers:
self.env[model].browse(ids).message_subscribe([f.partner_id.id], [s.id for s in f.subtype_ids])
@api.one
def move(self, parent_id, res_id, model, move_back, move_followers=False):
if parent_id == res_id:
return
vals = {}
if move_back:
# clear variables if we move everything back
vals['is_moved'] = False
vals['moved_by_user_id'] = None
vals['moved_by_message_id'] = None
vals['moved_from_res_id'] = None
vals['moved_from_model'] = None
vals['moved_from_parent_id'] = None
else:
vals['parent_id'] = parent_id
vals['res_id'] = res_id
vals['model'] = model
vals['is_moved'] = True
vals['moved_by_user_id'] = self.env.user.id
vals['moved_by_message_id'] = self.id
for r in self.all_child_ids:
r_vals = vals.copy()
if not r.is_moved:
# moved_from_* variables contain not last, but original
# reference
r_vals['moved_from_parent_id'] = r.parent_id.id
r_vals['moved_from_res_id'] = r.res_id
r_vals['moved_from_model'] = r.model
elif move_back:
r_vals['parent_id'] = r.moved_from_parent_id.id
r_vals['res_id'] = r.moved_from_res_id
r_vals['model'] = r.moved_from_model
print 'update message', r, r_vals
if move_followers:
r.sudo().move_followers(r_vals.get('model'), r_vals.get('res_id'))
r.sudo().write(r_vals)
r.attachment_ids.sudo().write({
'res_id': r_vals.get('res_id'),
'res_model': r_vals.get('model')
})
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'] or ''
extended_name = ' [%s] ID %s' % (record.get('model', 'UNDEF'), record.get('res_id', 'UNDEF'))
res.append((record['id'], name + extended_name))
return res
def _message_read_dict(self, cr, uid, message, parent_id=False, context=None):
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')
move_followers = fields.Boolean('Move Followers')
@api.model
def get_default_move_message_configs(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],
'move_followers': config_parameters.get_param('mail_relocation_move_followers')
}
@api.multi
def set_move_message_configs(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)
config_parameters.set_param('mail_relocation_move_followers', record.move_followers or '')
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

122
mail_move_message/mail_move_message_views.xml

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp><data>
<template id="assets_backend" name="custom bar assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet" href="/mail_move_message/static/src/css/mail_move_message.css"/>
<script type="text/javascript" src="/mail_move_message/static/src/js/mail_move_message.js"></script>
</xpath>
</template>
<record id="view_wizard" model="ir.ui.view">
<field name="name">mail_move_message.wizard.view</field>
<field name="model">mail_move_message.wizard</field>
<field name="arch" type="xml">
<form string="Move Message">
<field name="can_move" invisible="1"/>
<field name="message_is_moved" invisible="1"/>
<field name="message_name_from" invisible="1"/>
<field name="message_email_from" invisible="1"/>
<field name="message_to_read" invisible="1"/>
<field name="uid" invisible="1"/>
<p attrs="{'invisible':[('can_move', '!=', False)]}">You cannot move this message. It was already moved with a message bellow. Open one and apply changes there.</p>
<group attrs="{'invisible':[('can_move', '!=', False)]}">
<field name="message_moved_by_message_id" context="{'extended_name':1}"/>
<field name="message_moved_by_user_id"/>
<button name="open_moved_by_message_id" string="Open message" type="object" class="oe_highlight"/>
</group>
<group attrs="{'invisible':[('can_move', '=', False)]}" colspan="2">
<label for="model"/>
<div>
<field name="model" widget="polymorphic" polymorphic="res_id" class="oe_inline"/>
</div>
<label for="filter_by_partner"/>
<div>
<field name="filter_by_partner"/>
<field name="partner_id" style="width:50%"/>
<button string="Create Partner" attrs="{'invisible':[('partner_id','!=',False)]}" class="oe_highlight" special="quick_create" field="partner_id" context="{'force_email':True,'default_email':message_email_from,'default_name':message_name_from, 'update_message_author':True}"/>
</div>
<label for="res_id"/>
<div>
<field name="res_id" context="{'extended_name_with_contact':1}" widget="many2one" attrs="{'readonly': [('model','=',False)]}" style="width:50%"/>
<button string="Create new record" name="create_record" type="object" class="oe_highlight" attrs="{'invisible':['|',('model','=',False)]}" special="quick_create" field="res_id" use_for_mail_move_message="True"/>
</div>
<label for="move_back" attrs="{'invisible':[('message_is_moved','=',False)]}"/>
<div attrs="{'invisible':[('message_is_moved','=',False)]}">
<field name="move_back"/>
</div>
<label for="move_followers"/>
<div>
<field name="move_followers"/>
</div>
</group>
<button name="move" string="Move" type="object" class="oe_highlight" attrs="{'invisible':[('can_move', '=', False)]}"/>
<button string="Close" class="" special="cancel" />
<separator string="Message"/>
<group>
<field name="message_subject"/>
<field name="message_from"/>
<field name="message_id" invisible="1"/>
</group>
<div class="openerp mail_move_message">
<div class="oe_mail">
<div class="oe_msg">
<div class="oe_msg_content">
<div class="oe_msg_body">
<!-- use built-in css for messages -->
<field name="message_body"/>
</div>
</div>
</div>
</div>
</div>
<footer>
<button name="read_close" string="Mark as read and Close" type="object" class="oe_highlight"/> or
<button special="cancel" string="Close" class="oe_link"/>
<button name="delete" string="Delete message" type="object" class="oe_highlight oe_right" confirm="Do you really want to delete this message?" attrs="{'invisible':[('uid','!=',1)]}"/>
</footer>
</form>
</field>
</record>
<!-- Relocation config wizard -->
<record id="view_mail_move_message_config_settings" model="ir.ui.view">
<field name="name">relocation settings</field>
<field name="model">mail_move_message.config.settings</field>
<field name="arch" type="xml">
<form string="Configure Mail Relocation" class="oe_form_configuration">
<header>
<button string="Apply" type="object" name="execute" class="oe_highlight"/>
or
<button string="Cancel" type="object" name="cancel" class="oe_link"/>
</header>
<div name="general">
<separator string="Models"/>
<field name="model_ids" widget="many2many_tags"/>
<separator string="Options"/>
<label for="move_followers"/>
<field name="move_followers"/>
</div>
</form>
</field>
</record>
<record id="action_mail_move_message_config" model="ir.actions.act_window">
<field name="name">Mail Relocation</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">mail_move_message.config.settings</field>
<field name="view_id" ref="view_mail_move_message_config_settings"/>
<field name="view_mode">form</field>
<field name="target">inline</field>
</record>
<!-- Add menu entry in Settings/Email -->
<menuitem name="Mail Relocation" id="menu_mail_move_message" parent="base.menu_email" sequence="99" action="action_mail_move_message_config"/>
</data>
</openerp>

BIN
mail_move_message/static/description/delete-message.png

After

Width: 1012  |  Height: 546  |  Size: 73 KiB

BIN
mail_move_message/static/description/html-message-viewer.png

After

Width: 1012  |  Height: 546  |  Size: 62 KiB

BIN
mail_move_message/static/description/html-message-viewer1.png

After

Width: 1012  |  Height: 546  |  Size: 51 KiB

BIN
mail_move_message/static/description/html-message.png

After

Width: 890  |  Height: 473  |  Size: 58 KiB

BIN
mail_move_message/static/description/icon.png

After

Width: 120  |  Height: 120  |  Size: 3.0 KiB

BIN
mail_move_message/static/description/inbox-move.png

After

Width: 1054  |  Height: 562  |  Size: 85 KiB

BIN
mail_move_message/static/description/inbox.png

After

Width: 750  |  Height: 400  |  Size: 69 KiB

140
mail_move_message/static/description/index.html

@ -0,0 +1,140 @@
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<h2 class="oe_slogan">Mail relocation</h2>
<h3 class="oe_slogan">Relocate customer's mails to a correct place (lead, task etc.)</h3>
</div>
<div class="oe_span12">
<p class="oe_mt32">
The module helps you to organise mails from customers.
</p>
<p>
If customer send mail to user's personal alias (e.g. admin@yourcompany.example.com), a user would be able to relocate such mail to corresponding record.
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<h2>Usage</h2>
<p class="oe_mt32">
Click on an icon of two cross arrows.
</p>
</div>
<div class="oe_span12">
<div class="oe_demo oe_picture oe_screenshot">
<img src="inbox.png?3"/>
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<p class="oe_mt32">
Find a record you need and click on "Move" button.
</p>
</div>
<div class="oe_span12">
<div class="oe_demo oe_picture oe_screenshot">
<img src="inbox-move.png?4"/>
</div>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<p class="oe_mt32">
Done! You've attached mail and its child mails to the record.
</p>
</div>
<div class="oe_span12">
<div class="oe_demo oe_picture oe_screenshot">
<img src="record1.png?3"/>
</div>
<p class="oe_mt32">
Scroll down... Moved mails are marked by highlighted icon.
</p>
<div class="oe_demo oe_picture oe_screenshot">
<img src="record2.png?4"/>
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<p class="oe_mt32">
You could easily return mails back if you change your mind.
</p>
</div>
<div class="oe_span12">
<div class="oe_demo oe_picture oe_screenshot">
<img src="record-move-back.png?1"/>
</div>
<p class="oe_mt32">
Further information and discussion: <a href="https://yelizariev.github.io/odoo/module/2015/04/10/mail-relocation.html">https://yelizariev.github.io/odoo/module/2015/04/10/mail-relocation.html</a>
</p>
</div>
</div>
</section>
<section class="oe_container oe_dark">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<h2>Tips and tricks</h2>
<p class="oe_mt32">
Also, the module can be used as a viewer for wide html messages
</p>
</div>
<div class="oe_span12">
<div class="oe_demo oe_picture oe_screenshot">
<img src="html-message.png?1"/>
</div>
<p class="oe_mt32">
Check message and then close window.
</p>
<div class="oe_demo oe_picture oe_screenshot">
<img src="html-message-viewer1.png"/>
</div>
<p class="oe_mt32">
Also, you can mark as read and close
</p>
<div class="oe_demo oe_picture oe_screenshot">
<img src="html-message-viewer.png?2"/>
</div>
<p class="oe_mt32">
In addition, the module can be used to delete a message (it's available for superuser only)
</p>
<div class="oe_demo oe_picture oe_screenshot">
<img src="delete-message.png"/>
</div>
</div>
</div>
</section>
<section class="oe_container">
<div class="oe_row oe_spaced">
<div class="oe_span12">
<h2>Need our service?</h2>
<p class="oe_mt32">Contact us by <a href="mailto:it@it-projects.info">email</a> or fill out <a href="https://www.it-projects.info/page/website.contactus " target="_blank">request form</a></p>
<ul>
<li><a href="mailto:it@it-projects.info">it@it-projects.info <i class="fa fa-envelope-o"></i></a></li>
<li><a href="https://www.it-projects.info/page/website.contactus " target="_blank">
https://www.it-projects.info/page/website.contactus <i class="fa fa-list-alt"></i></a></li>
</ul>
</div>
</div>
</section>

BIN
mail_move_message/static/description/record-move-back.png

After

Width: 904  |  Height: 482  |  Size: 68 KiB

BIN
mail_move_message/static/description/record1.png

After

Width: 1007  |  Height: 537  |  Size: 58 KiB

BIN
mail_move_message/static/description/record2.png

After

Width: 750  |  Height: 400  |  Size: 70 KiB

13
mail_move_message/static/src/css/mail_move_message.css

@ -0,0 +1,13 @@
.openerp .oe_mail .oe_msg .oe_msg_icons .oe_move.oe_moved a {
color: #ffefe;
text-shadow: 0px 1px #961b1b,0px -1px #961b1b, -1px 0px #961b1b, 1px 0px #961b1b, 0px 3px 3px rgba(0,0,0,0.1);
}
.openerp .oe_mail .oe_msg .oe_msg_icons .oe_move:hover a {
color: #ffa1a1;
text-shadow: 0px 1px #ff0000,0px -1px #ff0000, -1px 0px #ff0000, 1px 0px #ff0000, 0px 3px 3px rgba(0,0,0,0.1);
}
.openerp.mail_move_message{
width: 864px;
}

91
mail_move_message/static/src/js/mail_move_message.js

@ -0,0 +1,91 @@
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 self = this;
var context = {
'default_message_id': this.id
}
var action = {
name: _t('Relocate Message'),
type: 'ir.actions.act_window',
res_model: 'mail_move_message.wizard',
view_mode: 'form',
view_type: 'form',
views: [[false, 'form']],
target: 'new',
context: context,
};
self.do_action(action, {
'on_close': function(){
self.check_for_rerender();
}
});
}
})
mail.MessageCommon.include({
init: function (parent, datasets, options) {
this._super(parent, datasets, options);
this.is_moved = datasets.is_moved || false;
}
})
session.web.form.WidgetButton.include({
on_click: function() {
if(this.node.attrs.special == 'quick_create'){
var self = this;
var related_field = this.field_manager.fields[this.node.attrs['field']];
var context_built = $.Deferred();
if(this.node.attrs.use_for_mail_move_message) {
var model = new session.web.Model(this.view.dataset.model);
var partner_id = self.field_manager.fields['partner_id'].get_value();
var message_name_from = self.field_manager.fields['message_name_from'].get_value();
var message_email_from = self.field_manager.fields['message_email_from'].get_value();
context_built = model.call('create_partner', [self.view.dataset.context.default_message_id,
related_field.field.relation, partner_id, message_name_from, message_email_from]);
}
else {
context_built.resolve(this.build_context());
}
$.when(context_built).pipe(function (context) {
if(self.node.attrs.use_for_mail_move_message) {
self.field_manager.fields['partner_id'].set_value(context['partner_id']);
}
var pop = new session.web.form.FormOpenPopup(this);
pop.show_element(
related_field.field.relation,
false,
context,
{
title: _t("Create new record"),
}
);
pop.on('closed', self, function () {
self.force_disabled = false;
self.check_disable();
});
pop.on('create_completed', self, function(id) {
related_field.set_value(id);
if(self.field_manager.fields['filter_by_partner']) {
self.field_manager.fields['filter_by_partner'].set_value(true);
}
});
});
}
else {
this._super.apply(this, arguments);
}
},
});
}

8
mail_move_message/static/src/xml/mail_move_message_main.xml

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<template>
<t t-extend="mail.thread.message">
<t t-jquery=".oe_msg_icons" t-operation="append">
<span t-attf-class="oe_move #{widget.is_moved?'oe_moved':''}"><a title="Move to thread" class="oe_e">f</a></span>
</t>
</t>
</template>
Loading…
Cancel
Save