From c956fb93f6275fa4c740cad47d47de8dcc6c48ed Mon Sep 17 00:00:00 2001
From: Carlos Lopez
Date: Fri, 24 Jan 2025 12:38:24 -0500
Subject: [PATCH] =?UTF-8?q?[IMP]=20mail=5Fforward:=20Add=20option=20to=20f?=
=?UTF-8?q?orward=20a=20message=20to=20another=20thread=20This=20option=20?=
=?UTF-8?q?posts=20a=20new=20message=20in=20the=20other=20thread,=20includ?=
=?UTF-8?q?ing=20the=20attachments,=20but=20does=20not=20add=20them=20as?=
=?UTF-8?q?=20followers=E2=80=94only=20notifying=20the=20current=20followe?=
=?UTF-8?q?rs=20of=20the=20other=20thread.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
mail_forward/README.rst | 24 ++-
mail_forward/__manifest__.py | 1 +
mail_forward/i18n/es.po | 30 ++-
mail_forward/i18n/mail_forward.pot | 20 ++
mail_forward/models/mail_message.py | 2 -
mail_forward/models/mail_thread.py | 5 +-
mail_forward/readme/DESCRIPTION.md | 6 +-
mail_forward/readme/USAGE.md | 7 +-
mail_forward/static/description/index.html | 19 +-
mail_forward/tests/test_mail_forward.py | 55 ++++++
mail_forward/wizards/mail_compose_message.py | 175 ++++++++++++++++--
.../wizards/mail_compose_message_view.xml | 16 +-
12 files changed, 317 insertions(+), 43 deletions(-)
diff --git a/mail_forward/README.rst b/mail_forward/README.rst
index 383983f522..689c461559 100644
--- a/mail_forward/README.rst
+++ b/mail_forward/README.rst
@@ -29,8 +29,12 @@ Mail Forward Message
|badge1| |badge2| |badge3| |badge4| |badge5|
This module allows users to forward messages from the chatter of any
-document to other users, adding them as followers of the document
-without notifying the current followers.
+document to:
+
+- Other users in the same thread, adding them as followers of the
+ document without notifying the current followers.
+- Another thread, but not adding them as followers—only notifying the
+ current followers of the other thread.
**Table of contents**
@@ -47,9 +51,11 @@ To use this module, follow these steps:
notes).
- A Forward icon will appear next to the message.
- Click the button to display a wizard with the message.
-- Select the users to forward the message to.
-- Click the 'Send Mail' button to send the message to the selected
- users.
+- Select the forward type (current thread or another thread).
+- Select the users to forward the message to, or select the other thread
+ according to the previous step.
+- Click the 'Send Mail' button to send the message to the selected users
+ or thread.
Bug Tracker
===========
@@ -89,6 +95,14 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
+.. |maintainer-carlos-lopez-tecnativa| image:: https://github.com/carlos-lopez-tecnativa.png?size=40px
+ :target: https://github.com/carlos-lopez-tecnativa
+ :alt: carlos-lopez-tecnativa
+
+Current `maintainer `__:
+
+|maintainer-carlos-lopez-tecnativa|
+
This module is part of the `OCA/social `_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/mail_forward/__manifest__.py b/mail_forward/__manifest__.py
index 19534c2d1f..1ac16f1087 100644
--- a/mail_forward/__manifest__.py
+++ b/mail_forward/__manifest__.py
@@ -22,4 +22,5 @@
"installable": True,
"auto_install": False,
"license": "AGPL-3",
+ "maintainers": ["carlos-lopez-tecnativa"],
}
diff --git a/mail_forward/i18n/es.po b/mail_forward/i18n/es.po
index 79f1c74336..356da7e1b0 100644
--- a/mail_forward/i18n/es.po
+++ b/mail_forward/i18n/es.po
@@ -4,7 +4,7 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: Odoo Server 15.0\n"
+"Project-Id-Version: Odoo Server 17.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-10-02 12:25+0000\n"
"PO-Revision-Date: 2024-10-02 07:27-0500\n"
@@ -24,6 +24,16 @@ msgstr ""
msgid "---------- Forwarded message ---------"
msgstr "---------- Mensaje reenviado ---------"
+#. module: mail_forward
+#: model:ir.model.fields.selection,name:mail_forward.selection__mail_compose_message__forward_type__another_thread
+msgid "Another thread"
+msgstr "Otro hilo"
+
+#. module: mail_forward
+#: model:ir.model.fields.selection,name:mail_forward.selection__mail_compose_message__forward_type__current_thread
+msgid "Current thread"
+msgstr "Hilo actual"
+
#. module: mail_forward
#. odoo-python
#: code:addons/mail_forward/models/mail_message.py:0
@@ -34,12 +44,12 @@ msgstr "Fecha"
#. module: mail_forward
#: model:ir.model,name:mail_forward.model_mail_thread
msgid "Email Thread"
-msgstr "Hilo de correos electrónicos"
+msgstr "Hilo de correo electrónico"
#. module: mail_forward
#: model:ir.model,name:mail_forward.model_mail_compose_message
msgid "Email composition wizard"
-msgstr "Asistente de composición de correos electrónicos"
+msgstr "Asistente de redacción de correo electrónico"
#. module: mail_forward
#. odoo-javascript
@@ -47,7 +57,7 @@ msgstr "Asistente de composición de correos electrónicos"
#: code:addons/mail_forward/static/src/core/common/message_actions.esm.js:0
#, python-format
msgid "Forward"
-msgstr ""
+msgstr "Reenviar"
#. module: mail_forward
#. odoo-javascript
@@ -79,6 +89,11 @@ msgstr ""
msgid "Forward Message Right"
msgstr ""
+#. module: mail_forward
+#: model:ir.model.fields,field_description:mail_forward.field_mail_compose_message__forward_type
+msgid "Forward Type"
+msgstr "Tipo de reenvío"
+
#. module: mail_forward
#. odoo-python
#: code:addons/mail_forward/models/mail_message.py:0
@@ -91,7 +106,7 @@ msgstr "De"
#: code:addons/mail_forward/wizards/mail_compose_message.py:0
#, python-format
msgid "Fwd:"
-msgstr ""
+msgstr "Re:"
#. module: mail_forward
#: model:ir.model,name:mail_forward.model_mail_message
@@ -112,6 +127,11 @@ msgstr ""
msgid "Subject"
msgstr "Asunto"
+#. module: mail_forward
+#: model:ir.model.fields,field_description:mail_forward.field_mail_compose_message__forward_thread
+msgid "Thread to forward"
+msgstr "Hilo a reenviar"
+
#. module: mail_forward
#. odoo-python
#: code:addons/mail_forward/models/mail_message.py:0
diff --git a/mail_forward/i18n/mail_forward.pot b/mail_forward/i18n/mail_forward.pot
index 17da3d1eee..83413c8170 100644
--- a/mail_forward/i18n/mail_forward.pot
+++ b/mail_forward/i18n/mail_forward.pot
@@ -20,6 +20,16 @@ msgstr ""
msgid "---------- Forwarded message ---------"
msgstr ""
+#. module: mail_forward
+#: model:ir.model.fields.selection,name:mail_forward.selection__mail_compose_message__forward_type__another_thread
+msgid "Another thread"
+msgstr ""
+
+#. module: mail_forward
+#: model:ir.model.fields.selection,name:mail_forward.selection__mail_compose_message__forward_type__current_thread
+msgid "Current thread"
+msgstr ""
+
#. module: mail_forward
#. odoo-python
#: code:addons/mail_forward/models/mail_message.py:0
@@ -76,6 +86,11 @@ msgstr ""
msgid "Forward Message Right"
msgstr ""
+#. module: mail_forward
+#: model:ir.model.fields,field_description:mail_forward.field_mail_compose_message__forward_type
+msgid "Forward Type"
+msgstr ""
+
#. module: mail_forward
#. odoo-python
#: code:addons/mail_forward/models/mail_message.py:0
@@ -109,6 +124,11 @@ msgstr ""
msgid "Subject"
msgstr ""
+#. module: mail_forward
+#: model:ir.model.fields,field_description:mail_forward.field_mail_compose_message__forward_thread
+msgid "Thread to forward"
+msgstr ""
+
#. module: mail_forward
#. odoo-python
#: code:addons/mail_forward/models/mail_message.py:0
diff --git a/mail_forward/models/mail_message.py b/mail_forward/models/mail_message.py
index 57a68cfbeb..a6c18e3dbc 100644
--- a/mail_forward/models/mail_message.py
+++ b/mail_forward/models/mail_message.py
@@ -19,8 +19,6 @@ def action_wizard_forward(self):
"default_model": self.model,
"default_res_ids": [self.res_id],
"default_composition_mode": "comment",
- "default_body": self._build_message_body_for_forward(),
- "default_attachment_ids": self.attachment_ids.ids,
"default_is_log": False,
"default_notify": True,
"force_email": True,
diff --git a/mail_forward/models/mail_thread.py b/mail_forward/models/mail_thread.py
index babb29db52..919c8747de 100644
--- a/mail_forward/models/mail_thread.py
+++ b/mail_forward/models/mail_thread.py
@@ -9,7 +9,10 @@ class MailThread(models.AbstractModel):
def _notify_get_recipients(self, message, msg_vals, **kwargs):
recipients_data = super()._notify_get_recipients(message, msg_vals, **kwargs)
# only notify to explicit partners, remove others(followers).
- if self.env.context.get("message_forwarded_id"):
+ if (
+ self.env.context.get("message_forwarded_id")
+ and self.env.context.get("forward_type", "") == "current_thread"
+ ):
current_partners_ids = message.partner_ids.ids
new_recipeints = []
for recipeint in recipients_data:
diff --git a/mail_forward/readme/DESCRIPTION.md b/mail_forward/readme/DESCRIPTION.md
index fe56c55461..872600afc0 100644
--- a/mail_forward/readme/DESCRIPTION.md
+++ b/mail_forward/readme/DESCRIPTION.md
@@ -1,3 +1,3 @@
-This module allows users to forward messages from the chatter of any
-document to other users, adding them as followers of the document
-without notifying the current followers.
+This module allows users to forward messages from the chatter of any document to:
+- Other users in the same thread, adding them as followers of the document without notifying the current followers.
+- Another thread, but not adding them as followers—only notifying the current followers of the other thread.
\ No newline at end of file
diff --git a/mail_forward/readme/USAGE.md b/mail_forward/readme/USAGE.md
index 0befa78624..18fc63e580 100644
--- a/mail_forward/readme/USAGE.md
+++ b/mail_forward/readme/USAGE.md
@@ -5,6 +5,7 @@ To use this module, follow these steps:
notes).
- A Forward icon will appear next to the message.
- Click the button to display a wizard with the message.
-- Select the users to forward the message to.
-- Click the 'Send Mail' button to send the message to the selected
- users.
+- Select the forward type (current thread or another thread).
+- Select the users to forward the message to, or select the other thread according to the previous step.
+- Click the 'Send Mail' button to send the message to the selected users or thread.
+
\ No newline at end of file
diff --git a/mail_forward/static/description/index.html b/mail_forward/static/description/index.html
index 3d1338e7da..53b9bbd736 100644
--- a/mail_forward/static/description/index.html
+++ b/mail_forward/static/description/index.html
@@ -371,8 +371,13 @@ Mail Forward Message
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
![Try me on Runboat](https://img.shields.io/badge/runboat-Try%20me-875A7B.png)
This module allows users to forward messages from the chatter of any
-document to other users, adding them as followers of the document
-without notifying the current followers.
+document to:
+
+- Other users in the same thread, adding them as followers of the
+document without notifying the current followers.
+- Another thread, but not adding them as followers—only notifying the
+current followers of the other thread.
+
Table of contents
@@ -395,9 +400,11 @@
notes).
- A Forward icon will appear next to the message.
- Click the button to display a wizard with the message.
-- Select the users to forward the message to.
-- Click the ‘Send Mail’ button to send the message to the selected
-users.
+- Select the forward type (current thread or another thread).
+- Select the users to forward the message to, or select the other thread
+according to the previous step.
+- Click the ‘Send Mail’ button to send the message to the selected users
+or thread.
@@ -434,6 +441,8 @@
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
+
Current maintainer:
+
![carlos-lopez-tecnativa](https://github.com/carlos-lopez-tecnativa.png?size=40px)
This module is part of the OCA/social project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
diff --git a/mail_forward/tests/test_mail_forward.py b/mail_forward/tests/test_mail_forward.py
index 88f311bf49..12a459c958 100644
--- a/mail_forward/tests/test_mail_forward.py
+++ b/mail_forward/tests/test_mail_forward.py
@@ -69,6 +69,61 @@ def test_01_mail_forward(self):
self.assertIn(self.partner_forward, forward_message.partner_ids)
self.assertIn("---------- Forwarded message ---------", forward_message.body)
+ def test_mail_forward_another_thread(self):
+ """
+ Check that the email is forwarded to another thread.
+ and the email is sent to the followers of the another thread.
+ """
+ ctx = {
+ "default_model": self.test_record._name,
+ "default_res_ids": [self.test_record.id],
+ }
+ composer_form = Form(self.env["mail.compose.message"].with_context(**ctx))
+ composer_form.body = "Hello
"
+ composer_form.subject = "Test Forward"
+ composer_form.partner_ids.add(self.partner_follower1)
+ composer = composer_form.save()
+ with self.mock_mail_gateway():
+ composer._action_send_mail()
+ # Verify recipients of mail.message
+ message = self.test_record.message_ids[0]
+ self.assertEqual(len(message.partner_ids), 1)
+ self.assertIn(self.partner_follower1, message.partner_ids)
+ self.assertNotIn(self.partner_follower2, message.partner_ids)
+ self.assertNotIn(self.partner_forward, message.partner_ids)
+ self.assertNotIn("---------- Forwarded message ---------", message.body)
+ # Forward the email to another record(self.partner_forward)
+ action_forward = message.action_wizard_forward()
+ Message = self.env["mail.compose.message"].with_context(
+ **action_forward["context"]
+ )
+ composer_form = Form(Message, view=action_forward["views"][0][0])
+ composer_form.partner_ids.add(self.partner_follower2)
+ composer_form.forward_type = "another_thread"
+ composer_form.forward_thread = (
+ f"{self.partner_forward._name},{self.partner_forward.id}"
+ )
+ composer = composer_form.save()
+ message_domain = [
+ ("model", "=", self.partner_forward._name),
+ ("res_id", "=", self.partner_forward.id),
+ ]
+ with RecordCapturer(self.env["mail.message"], message_domain) as capture:
+ with self.mock_mail_gateway():
+ composer._action_send_mail()
+ # Verify recipients of mail.message
+ forward_message = capture.records
+ self.assertEqual(forward_message.subject, "Fwd: Test Forward")
+ self.assertEqual(len(forward_message.partner_ids), 1)
+ self.assertNotIn(self.partner_follower1, forward_message.partner_ids)
+ # the partner partner_follower2 is added to the message
+ # but is not added as a follower automatically.
+ self.assertIn(self.partner_follower2, forward_message.partner_ids)
+ self.assertNotIn(
+ self.partner_follower2, self.partner_forward.message_partner_ids
+ )
+ self.assertIn("---------- Forwarded message ---------", forward_message.body)
+
def test_02_mail_forward_tour(self):
self.test_record.message_post(
body="Hello World", message_type="comment", subtype_xmlid="mail.mt_comment"
diff --git a/mail_forward/wizards/mail_compose_message.py b/mail_forward/wizards/mail_compose_message.py
index cb36069e2c..8cd89ac929 100644
--- a/mail_forward/wizards/mail_compose_message.py
+++ b/mail_forward/wizards/mail_compose_message.py
@@ -1,11 +1,164 @@
# Copyright 2024 Tecnativa - Carlos Lopez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
-from odoo import Command, _, api, models
+from odoo import _, api, fields, models
class MailComposeMessage(models.TransientModel):
_inherit = "mail.compose.message"
+ forward_type = fields.Selection(
+ [
+ ("current_thread", "Current thread"),
+ ("another_thread", "Another thread"),
+ ],
+ default="current_thread",
+ )
+ forward_thread = fields.Reference(
+ selection="_selection_forward_thread", string="Thread to forward"
+ )
+
+ @api.model
+ def _selection_forward_thread(self):
+ # Get all models available to be selected by the user.
+ # Only consider models that support posted messages and are not transient.
+ models = (
+ self.env["ir.model"]
+ .sudo()
+ .search(
+ [("transient", "=", False), ("is_mail_thread", "=", True)],
+ order="name asc",
+ )
+ )
+ selection_values = []
+ for model in models:
+ if (
+ model.model in self.env and self.env[model.model]._auto
+ ): # No Abstract models or reports
+ selection_values.append((model.model, model.name))
+ return selection_values
+
+ @api.depends(
+ "composition_mode",
+ "model",
+ "res_domain",
+ "res_ids",
+ "template_id",
+ "forward_type",
+ )
+ @api.depends_context("message_forwarded_id")
+ def _compute_attachment_ids(self):
+ # Save the attachments before calling super() to avoid losing them
+ # because when template_id is not set,
+ # attachment_ids is set to False in the super() call.
+ old_attachments = {composer.id: composer.attachment_ids for composer in self}
+ res = super()._compute_attachment_ids()
+ if self.env.context.get("message_forwarded_id"):
+ # Add the attachments from the original message.
+ message_forwarded = self.env["mail.message"].browse(
+ self.env.context["message_forwarded_id"]
+ )
+ for composer in self:
+ composer.attachment_ids |= old_attachments[composer.id]
+ for attachment in message_forwarded.attachment_ids:
+ composer.attachment_ids |= attachment
+ return res
+
+ @api.depends(
+ "composition_mode",
+ "model",
+ "res_domain",
+ "res_ids",
+ "template_id",
+ "forward_type",
+ "forward_thread",
+ )
+ @api.depends_context("message_forwarded_id")
+ def _compute_body(self):
+ res = super()._compute_body()
+ if self.env.context.get("message_forwarded_id"):
+ # Set the body by default, taking it from the original message.
+ message_forwarded = self.env["mail.message"].browse(
+ self.env.context["message_forwarded_id"]
+ )
+ for composer in self.filtered(lambda c: not c.body):
+ composer.body = message_forwarded._build_message_body_for_forward()
+ return res
+
+ @api.depends(
+ "composition_mode",
+ "model",
+ "parent_id",
+ "record_name",
+ "res_domain",
+ "res_ids",
+ "template_id",
+ "forward_type",
+ "forward_thread",
+ )
+ @api.depends_context("message_forwarded_id")
+ def _compute_subject(self):
+ res = super()._compute_subject()
+ if self.env.context.get("message_forwarded_id"):
+ # Set the subject by default,
+ # because when change the model and res_ids,
+ # the subject is taken from the new record.
+ message_forwarded = self.env["mail.message"].browse(
+ self.env.context["message_forwarded_id"]
+ )
+ for composer in self:
+ composer.subject = f"{_('Fwd:')} {message_forwarded.subject}"
+ return res
+
+ @api.depends("composition_mode", "parent_id", "forward_type", "forward_thread")
+ @api.depends_context("message_forwarded_id")
+ def _compute_model(self):
+ res = super()._compute_model()
+ if self.env.context.get("message_forwarded_id"):
+ # Set the model to the record to be forwarded
+ # if the composer is set to forward a record
+ # it sends the message to the record to be forwarded
+ for composer in self.filtered(
+ lambda c: c.forward_type == "another_thread" and c.forward_thread
+ ):
+ composer.model = composer.forward_thread._name
+ return res
+
+ @api.depends("composition_mode", "parent_id", "forward_type", "forward_thread")
+ @api.depends_context("message_forwarded_id")
+ def _compute_res_ids(self):
+ res = super()._compute_res_ids()
+ if self.env.context.get("message_forwarded_id"):
+ # Set res_ids to the record to be forwarded
+ # if the composer is set to forward a record
+ # it sends the message to the record to be forwarded
+ for composer in self.filtered(
+ lambda c: c.forward_type == "another_thread" and c.forward_thread
+ ):
+ composer.res_ids = composer.forward_thread.ids
+ return res
+
+ @api.depends(
+ "composition_mode",
+ "model",
+ "parent_id",
+ "res_domain",
+ "res_ids",
+ "template_id",
+ "forward_type",
+ )
+ @api.depends_context("message_forwarded_id")
+ def _compute_partner_ids(self):
+ # Save the partner_ids before calling super() to avoid losing them
+ # because when template_id is not set,
+ # partner_ids is set to False in the super() call.
+ old_partners = {composer.id: composer.partner_ids for composer in self}
+ res = super()._compute_partner_ids()
+ if self.env.context.get("message_forwarded_id"):
+ # Add the attachments from the original message.
+ for composer in self:
+ composer.partner_ids |= old_partners[composer.id]
+ return res
+
@api.model
def get_record_data(self, values):
result = super().get_record_data(values)
@@ -20,20 +173,6 @@ def get_record_data(self, values):
return result
def _action_send_mail(self, auto_commit=False):
- # duplicate attachments from original message
- message_forwarded_id = self.env.context.get("message_forwarded_id")
- if message_forwarded_id:
- message_forwarded = self.env["mail.message"].browse(message_forwarded_id)
- for wizard in self:
- new_attachment_ids = []
- for attachment in wizard.attachment_ids:
- if attachment in message_forwarded.attachment_ids:
- new_attachment = attachment.copy(
- {"res_model": "mail.compose.message", "res_id": wizard.id}
- )
- new_attachment_ids.append(new_attachment.id)
- else:
- new_attachment_ids.append(attachment.id)
- new_attachment_ids.reverse()
- wizard.write({"attachment_ids": [Command.set(new_attachment_ids)]})
- return super()._action_send_mail(auto_commit=auto_commit)
+ return super(
+ MailComposeMessage, self.with_context(forward_type=self.forward_type)
+ )._action_send_mail(auto_commit=auto_commit)
diff --git a/mail_forward/wizards/mail_compose_message_view.xml b/mail_forward/wizards/mail_compose_message_view.xml
index 1327be8d2e..24dd57e469 100644
--- a/mail_forward/wizards/mail_compose_message_view.xml
+++ b/mail_forward/wizards/mail_compose_message_view.xml
@@ -7,8 +7,22 @@
+
+
+
+
- 1
+ forward_type == 'current_thread'
1