You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
531 lines
19 KiB
531 lines
19 KiB
# -*- coding: utf-8 -*-
|
|
from openerp import api, fields, models
|
|
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)
|
|
if res_id:
|
|
res["res_id"] = 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="_compute_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.needaction")
|
|
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.multi
|
|
def _compute_can_move(self):
|
|
for r in self:
|
|
# message was not moved before OR message is a top message of previous move
|
|
r.can_move = (
|
|
not r.message_id.moved_by_message_id
|
|
or r.message_id.moved_by_message_id.id == r.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.multi
|
|
def check_access(self):
|
|
for r in self:
|
|
r.check_access_one()
|
|
|
|
@api.multi
|
|
def check_access_one(self):
|
|
self.ensure_one()
|
|
operation = "write"
|
|
|
|
if not (self.model and self.res_id):
|
|
return True
|
|
model_obj = self.env[self.model]
|
|
mids = model_obj.browse(self.res_id).exists()
|
|
if hasattr(model_obj, "check_mail_message_access"):
|
|
model_obj.check_mail_message_access(mids.ids, operation)
|
|
else:
|
|
self.env["mail.thread"].check_mail_message_access(
|
|
mids.ids, operation, model_name=self.model
|
|
)
|
|
|
|
@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):
|
|
r.message_id.needaction = False
|
|
return {
|
|
"type": "ir.actions.client",
|
|
"name": "All messages",
|
|
"tag": "reload",
|
|
}
|
|
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.multi
|
|
def delete(self):
|
|
for r in self:
|
|
r.delete_one()
|
|
|
|
@api.multi
|
|
def delete_one(self):
|
|
self.ensure_one()
|
|
msg_id = self.message_id.id
|
|
|
|
# Send notification
|
|
notification = {"id": msg_id}
|
|
self.env["bus.bus"].sendone(
|
|
(self._cr.dbname, "mail_move_message.delete_message"), notification
|
|
)
|
|
|
|
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.multi
|
|
def read_close(self):
|
|
for r in self:
|
|
r.read_close_one()
|
|
|
|
@api.multi
|
|
def read_close_one(self):
|
|
self.ensure_one()
|
|
self.message_id.set_message_done()
|
|
self.message_id.child_ids.set_message_done()
|
|
return {"type": "ir.actions.act_window_close"}
|
|
|
|
|
|
class MailMessage(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="_compute_all_childs",
|
|
help="all childs, including subchilds",
|
|
)
|
|
|
|
@api.multi
|
|
def _compute_all_childs(self, include_myself=True):
|
|
for r in self:
|
|
r._compute_all_childs_one(include_myself=include_myself)
|
|
|
|
@api.multi
|
|
def _compute_all_childs_one(self, include_myself=True):
|
|
self.ensure_one()
|
|
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.multi
|
|
def move(self, parent_id, res_id, model, move_back, move_followers=False):
|
|
for r in self:
|
|
r.move_one(
|
|
parent_id, res_id, model, move_back, move_followers=move_followers
|
|
)
|
|
|
|
@api.multi
|
|
def move_one(self, parent_id, res_id, model, move_back, move_followers=False):
|
|
self.ensure_one()
|
|
if parent_id == self.id:
|
|
# if for any reason method is called to move message with parent
|
|
# equal to oneself, we need stop to prevent infinitive loop in
|
|
# building message tree
|
|
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
|
|
|
|
# Update record_name in message
|
|
vals["record_name"] = self._get_record_name(vals)
|
|
|
|
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
|
|
|
|
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")}
|
|
)
|
|
|
|
# Send notification
|
|
notification = {
|
|
"id": self.id,
|
|
"res_id": vals.get("res_id"),
|
|
"model": vals.get("model"),
|
|
"is_moved": vals["is_moved"],
|
|
"record_name": vals["record_name"],
|
|
}
|
|
self.env["bus.bus"].sendone(
|
|
(self._cr.dbname, "mail_move_message"), notification
|
|
)
|
|
|
|
@api.multi
|
|
def name_get(self):
|
|
context = self.env.context
|
|
if not (context or {}).get("extended_name"):
|
|
return super(MailMessage, self).name_get()
|
|
reads = self.read(["record_name", "model", "res_id"])
|
|
res = []
|
|
for record in reads:
|
|
name = record["record_name"] or ""
|
|
extended_name = " [{}] ID {}".format(
|
|
record.get("model", "UNDEF"), record.get("res_id", "UNDEF"),
|
|
)
|
|
res.append((record["id"], name + extended_name))
|
|
return res
|
|
|
|
@api.multi
|
|
def message_format(self):
|
|
message_values = super(MailMessage, self).message_format()
|
|
message_index = {message["id"]: message for message in message_values}
|
|
for item in self:
|
|
msg = message_index.get(item.id)
|
|
if msg:
|
|
msg["is_moved"] = item.is_moved
|
|
return message_values
|
|
|
|
|
|
class MailMoveMessageConfiguration(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 ResPartner(models.Model):
|
|
_inherit = "res.partner"
|
|
|
|
@api.model
|
|
def create(self, vals):
|
|
res = super(ResPartner, 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
|