[IMP] mail_forward: Add option to forward a message to another thread

This option posts a new message in the other thread, including the attachments, but does not add them as followers—only notifying the current followers of the other thread.
pull/1557/head
Carlos Lopez 2025-01-24 12:38:24 -05:00
parent 679bcfa2dd
commit 300ef2ddda
16 changed files with 441 additions and 62 deletions

View File

@ -29,14 +29,29 @@ Mail Forward Message
|badge1| |badge2| |badge3| |badge4| |badge5| |badge1| |badge2| |badge3| |badge4| |badge5|
This module allows users to forward messages from the chatter of any This module allows users to forward messages from the chatter of any
document to other users, adding them as followers of the document document to:
without notifying the current followers.
- 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** **Table of contents**
.. contents:: .. contents::
:local: :local:
Configuration
=============
To enable a model to forward messages to another thread:
- With debug mode activated, go to
``Settings -> Technical -> Database Structure -> Models``.
- Search for the model you wish to enable.
- Mark the option ``Enable Forward To`` and save. Transient models or
those without mail thread won't have this check visible.
Usage Usage
===== =====
@ -47,9 +62,11 @@ To use this module, follow these steps:
notes). notes).
- A Forward icon will appear next to the message. - A Forward icon will appear next to the message.
- Click the button to display a wizard with the message. - Click the button to display a wizard with the message.
- Select the users to forward the message to. - Select the forward type (current thread or another thread).
- Click the 'Send Mail' button to send the message to the selected - Select the users to forward the message to, or select the other thread
users. according to the previous step.
- Click the 'Send Mail' button to send the message to the selected users
or thread.
Bug Tracker Bug Tracker
=========== ===========
@ -89,6 +106,14 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use. 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 <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-carlos-lopez-tecnativa|
This module is part of the `OCA/social <https://github.com/OCA/social/tree/17.0/mail_forward>`_ project on GitHub. This module is part of the `OCA/social <https://github.com/OCA/social/tree/17.0/mail_forward>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -7,9 +7,7 @@
"author": "Tecnativa, Odoo Community Association (OCA)", "author": "Tecnativa, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/social", "website": "https://github.com/OCA/social",
"depends": ["mail", "contacts"], "depends": ["mail", "contacts"],
"data": [ "data": ["wizards/mail_compose_message_view.xml", "views/ir_model_views.xml"],
"wizards/mail_compose_message_view.xml",
],
"assets": { "assets": {
"web.assets_backend": [ "web.assets_backend": [
"mail_forward/static/src/**/*.esm.js", "mail_forward/static/src/**/*.esm.js",
@ -22,4 +20,5 @@
"installable": True, "installable": True,
"auto_install": False, "auto_install": False,
"license": "AGPL-3", "license": "AGPL-3",
"maintainers": ["carlos-lopez-tecnativa"],
} }

View File

@ -4,10 +4,10 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 15.0\n" "Project-Id-Version: Odoo Server 17.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-10-02 12:25+0000\n" "POT-Creation-Date: 2025-01-27 17:26+0000\n"
"PO-Revision-Date: 2024-10-02 07:27-0500\n" "PO-Revision-Date: 2025-01-27 12:28-0500\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
"Language: es\n" "Language: es\n"
@ -15,7 +15,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 3.0.1\n" "X-Generator: Poedit 3.5\n"
#. module: mail_forward #. module: mail_forward
#. odoo-python #. odoo-python
@ -24,6 +24,16 @@ msgstr ""
msgid "---------- Forwarded message ---------" msgid "---------- Forwarded message ---------"
msgstr "---------- Mensaje reenviado ---------" 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 #. module: mail_forward
#. odoo-python #. odoo-python
#: code:addons/mail_forward/models/mail_message.py:0 #: code:addons/mail_forward/models/mail_message.py:0
@ -39,7 +49,22 @@ msgstr "Hilo de correos electrónicos"
#. module: mail_forward #. module: mail_forward
#: model:ir.model,name:mail_forward.model_mail_compose_message #: model:ir.model,name:mail_forward.model_mail_compose_message
msgid "Email composition wizard" 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
#: model:ir.model.fields,field_description:mail_forward.field_ir_model__enable_forward_to
msgid "Enable Forward To"
msgstr "Habilitar reenvío a"
#. module: mail_forward
#: model:ir.model.fields,help:mail_forward.field_ir_model__enable_forward_to
msgid "Enable forwarding messages to records of this model."
msgstr "Habilita el reenvío de mensajes a registros de este modelo."
#. module: mail_forward
#: model_terms:ir.ui.view,arch_db:mail_forward.mail_compose_message_forward_form
msgid "Followers to notify"
msgstr "Seguidores a notificar"
#. module: mail_forward #. module: mail_forward
#. odoo-javascript #. odoo-javascript
@ -47,7 +72,7 @@ msgstr "Asistente de composición de correos electrónicos"
#: code:addons/mail_forward/static/src/core/common/message_actions.esm.js:0 #: code:addons/mail_forward/static/src/core/common/message_actions.esm.js:0
#, python-format #, python-format
msgid "Forward" msgid "Forward"
msgstr "" msgstr "Reenviar"
#. module: mail_forward #. module: mail_forward
#. odoo-javascript #. odoo-javascript
@ -79,6 +104,11 @@ msgstr ""
msgid "Forward Message Right" msgid "Forward Message Right"
msgstr "" 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 #. module: mail_forward
#. odoo-python #. odoo-python
#: code:addons/mail_forward/models/mail_message.py:0 #: code:addons/mail_forward/models/mail_message.py:0
@ -91,13 +121,18 @@ msgstr "De"
#: code:addons/mail_forward/wizards/mail_compose_message.py:0 #: code:addons/mail_forward/wizards/mail_compose_message.py:0
#, python-format #, python-format
msgid "Fwd:" msgid "Fwd:"
msgstr "" msgstr "RV:"
#. module: mail_forward #. module: mail_forward
#: model:ir.model,name:mail_forward.model_mail_message #: model:ir.model,name:mail_forward.model_mail_message
msgid "Message" msgid "Message"
msgstr "Mensaje" msgstr "Mensaje"
#. module: mail_forward
#: model:ir.model,name:mail_forward.model_ir_model
msgid "Models"
msgstr "Modelos"
#. module: mail_forward #. module: mail_forward
#. odoo-python #. odoo-python
#: code:addons/mail_forward/wizards/mail_compose_message.py:0 #: code:addons/mail_forward/wizards/mail_compose_message.py:0
@ -112,6 +147,11 @@ msgstr ""
msgid "Subject" msgid "Subject"
msgstr "Asunto" 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 #. module: mail_forward
#. odoo-python #. odoo-python
#: code:addons/mail_forward/models/mail_message.py:0 #: code:addons/mail_forward/models/mail_message.py:0

View File

@ -6,6 +6,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 17.0\n" "Project-Id-Version: Odoo Server 17.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-01-27 17:26+0000\n"
"PO-Revision-Date: 2025-01-27 17:26+0000\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -20,6 +22,16 @@ msgstr ""
msgid "---------- Forwarded message ---------" msgid "---------- Forwarded message ---------"
msgstr "" 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 #. module: mail_forward
#. odoo-python #. odoo-python
#: code:addons/mail_forward/models/mail_message.py:0 #: code:addons/mail_forward/models/mail_message.py:0
@ -37,6 +49,21 @@ msgstr ""
msgid "Email composition wizard" msgid "Email composition wizard"
msgstr "" msgstr ""
#. module: mail_forward
#: model:ir.model.fields,field_description:mail_forward.field_ir_model__enable_forward_to
msgid "Enable Forward To"
msgstr ""
#. module: mail_forward
#: model:ir.model.fields,help:mail_forward.field_ir_model__enable_forward_to
msgid "Enable forwarding messages to records of this model."
msgstr ""
#. module: mail_forward
#: model_terms:ir.ui.view,arch_db:mail_forward.mail_compose_message_forward_form
msgid "Followers to notify"
msgstr ""
#. module: mail_forward #. module: mail_forward
#. odoo-javascript #. odoo-javascript
#: code:addons/mail_forward/static/src/components/forward_message/forward_message.xml:0 #: code:addons/mail_forward/static/src/components/forward_message/forward_message.xml:0
@ -76,6 +103,11 @@ msgstr ""
msgid "Forward Message Right" msgid "Forward Message Right"
msgstr "" 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 #. module: mail_forward
#. odoo-python #. odoo-python
#: code:addons/mail_forward/models/mail_message.py:0 #: code:addons/mail_forward/models/mail_message.py:0
@ -95,6 +127,11 @@ msgstr ""
msgid "Message" msgid "Message"
msgstr "" msgstr ""
#. module: mail_forward
#: model:ir.model,name:mail_forward.model_ir_model
msgid "Models"
msgstr ""
#. module: mail_forward #. module: mail_forward
#. odoo-python #. odoo-python
#: code:addons/mail_forward/wizards/mail_compose_message.py:0 #: code:addons/mail_forward/wizards/mail_compose_message.py:0
@ -109,6 +146,11 @@ msgstr ""
msgid "Subject" msgid "Subject"
msgstr "" 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 #. module: mail_forward
#. odoo-python #. odoo-python
#: code:addons/mail_forward/models/mail_message.py:0 #: code:addons/mail_forward/models/mail_message.py:0

View File

@ -1,2 +1,3 @@
from . import ir_model
from . import mail_message from . import mail_message
from . import mail_thread from . import mail_thread

View File

@ -0,0 +1,9 @@
from odoo import fields, models
class IrModel(models.Model):
_inherit = "ir.model"
enable_forward_to = fields.Boolean(
help="Enable forwarding messages to records of this model."
)

View File

@ -19,8 +19,6 @@ class MailMessage(models.Model):
"default_model": self.model, "default_model": self.model,
"default_res_ids": [self.res_id], "default_res_ids": [self.res_id],
"default_composition_mode": "comment", "default_composition_mode": "comment",
"default_body": self._build_message_body_for_forward(),
"default_attachment_ids": self.attachment_ids.ids,
"default_is_log": False, "default_is_log": False,
"default_notify": True, "default_notify": True,
"force_email": True, "force_email": True,

View File

@ -9,7 +9,10 @@ class MailThread(models.AbstractModel):
def _notify_get_recipients(self, message, msg_vals, **kwargs): def _notify_get_recipients(self, message, msg_vals, **kwargs):
recipients_data = super()._notify_get_recipients(message, msg_vals, **kwargs) recipients_data = super()._notify_get_recipients(message, msg_vals, **kwargs)
# only notify to explicit partners, remove others(followers). # 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 current_partners_ids = message.partner_ids.ids
new_recipeints = [] new_recipeints = []
for recipeint in recipients_data: for recipeint in recipients_data:

View File

@ -0,0 +1,5 @@
To enable a model to forward messages to another thread:
- With debug mode activated, go to `Settings -> Technical -> Database Structure -> Models`.
- Search for the model you wish to enable.
- Mark the option `Enable Forward To` and save. Transient models or those without mail thread won't have this check visible.

View File

@ -1,3 +1,3 @@
This module allows users to forward messages from the chatter of any This module allows users to forward messages from the chatter of any document to:
document to other users, adding them as followers of the document - Other users in the same thread, adding them as followers of the document without notifying the current followers.
without notifying the current followers. - Another thread, but not adding them as followers—only notifying the current followers of the other thread.

View File

@ -5,6 +5,7 @@ To use this module, follow these steps:
notes). notes).
- A Forward icon will appear next to the message. - A Forward icon will appear next to the message.
- Click the button to display a wizard with the message. - Click the button to display a wizard with the message.
- Select the users to forward the message to. - Select the forward type (current thread or another thread).
- Click the 'Send Mail' button to send the message to the selected - Select the users to forward the message to, or select the other thread according to the previous step.
users. - Click the 'Send Mail' button to send the message to the selected users or thread.

View File

@ -371,23 +371,40 @@ ul.auto-toc {
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/social/tree/17.0/mail_forward"><img alt="OCA/social" src="https://img.shields.io/badge/github-OCA%2Fsocial-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/social-17-0/social-17-0-mail_forward"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/social&amp;target_branch=17.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p> <p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/social/tree/17.0/mail_forward"><img alt="OCA/social" src="https://img.shields.io/badge/github-OCA%2Fsocial-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/social-17-0/social-17-0-mail_forward"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/social&amp;target_branch=17.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module allows users to forward messages from the chatter of any <p>This module allows users to forward messages from the chatter of any
document to other users, adding them as followers of the document document to:</p>
without notifying the current followers.</p> <ul class="simple">
<li>Other users in the same thread, adding them as followers of the
document without notifying the current followers.</li>
<li>Another thread, but not adding them as followers—only notifying the
current followers of the other thread.</li>
</ul>
<p><strong>Table of contents</strong></p> <p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents"> <div class="contents local topic" id="contents">
<ul class="simple"> <ul class="simple">
<li><a class="reference internal" href="#usage" id="toc-entry-1">Usage</a></li> <li><a class="reference internal" href="#configuration" id="toc-entry-1">Configuration</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li> <li><a class="reference internal" href="#usage" id="toc-entry-2">Usage</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul> <li><a class="reference internal" href="#bug-tracker" id="toc-entry-3">Bug Tracker</a></li>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li> <li><a class="reference internal" href="#credits" id="toc-entry-4">Credits</a><ul>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li> <li><a class="reference internal" href="#authors" id="toc-entry-5">Authors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li> <li><a class="reference internal" href="#contributors" id="toc-entry-6">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-7">Maintainers</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</div> </div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
<p>To enable a model to forward messages to another thread:</p>
<ul class="simple">
<li>With debug mode activated, go to
<tt class="docutils literal">Settings <span class="pre">-&gt;</span> Technical <span class="pre">-&gt;</span> Database Structure <span class="pre">-&gt;</span> Models</tt>.</li>
<li>Search for the model you wish to enable.</li>
<li>Mark the option <tt class="docutils literal">Enable Forward To</tt> and save. Transient models or
those without mail thread wont have this check visible.</li>
</ul>
</div>
<div class="section" id="usage"> <div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1> <h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
<p>To use this module, follow these steps:</p> <p>To use this module, follow these steps:</p>
<ul class="simple"> <ul class="simple">
<li>Navigate to the chatter of any document.</li> <li>Navigate to the chatter of any document.</li>
@ -395,13 +412,15 @@ without notifying the current followers.</p>
notes).</li> notes).</li>
<li>A Forward icon will appear next to the message.</li> <li>A Forward icon will appear next to the message.</li>
<li>Click the button to display a wizard with the message.</li> <li>Click the button to display a wizard with the message.</li>
<li>Select the users to forward the message to.</li> <li>Select the forward type (current thread or another thread).</li>
<li>Click the Send Mail button to send the message to the selected <li>Select the users to forward the message to, or select the other thread
users.</li> according to the previous step.</li>
<li>Click the Send Mail button to send the message to the selected users
or thread.</li>
</ul> </ul>
</div> </div>
<div class="section" id="bug-tracker"> <div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1> <h1><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/social/issues">GitHub Issues</a>. <p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/social/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported. In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed If you spotted it first, help us to smash it by providing a detailed and welcomed
@ -409,15 +428,15 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
<p>Do not contact contributors directly about support or help with technical issues.</p> <p>Do not contact contributors directly about support or help with technical issues.</p>
</div> </div>
<div class="section" id="credits"> <div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1> <h1><a class="toc-backref" href="#toc-entry-4">Credits</a></h1>
<div class="section" id="authors"> <div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2> <h2><a class="toc-backref" href="#toc-entry-5">Authors</a></h2>
<ul class="simple"> <ul class="simple">
<li>Tecnativa</li> <li>Tecnativa</li>
</ul> </ul>
</div> </div>
<div class="section" id="contributors"> <div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2> <h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
<ul class="simple"> <ul class="simple">
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul> <li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
<li>Carlos López</li> <li>Carlos López</li>
@ -426,7 +445,7 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
</ul> </ul>
</div> </div>
<div class="section" id="maintainers"> <div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2> <h2><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p> <p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"> <a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /> <img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
@ -434,6 +453,8 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose <p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and mission is to support the collaborative development of Odoo features and
promote its widespread use.</p> promote its widespread use.</p>
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
<p><a class="reference external image-reference" href="https://github.com/carlos-lopez-tecnativa"><img alt="carlos-lopez-tecnativa" src="https://github.com/carlos-lopez-tecnativa.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/social/tree/17.0/mail_forward">OCA/social</a> project on GitHub.</p> <p>This module is part of the <a class="reference external" href="https://github.com/OCA/social/tree/17.0/mail_forward">OCA/social</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p> <p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div> </div>

View File

@ -22,6 +22,7 @@ class TestMailForward(TestMailComposer, HttpCase):
cls.partner_forward = cls.env["res.partner"].create( cls.partner_forward = cls.env["res.partner"].create(
{"name": "Forward", "email": "forward@example.com"} {"name": "Forward", "email": "forward@example.com"}
) )
cls.env["ir.model"]._get("res.partner").enable_forward_to = True
def test_01_mail_forward(self): def test_01_mail_forward(self):
""" """
@ -39,7 +40,7 @@ class TestMailForward(TestMailComposer, HttpCase):
composer = composer_form.save() composer = composer_form.save()
with self.mock_mail_gateway(): with self.mock_mail_gateway():
composer._action_send_mail() composer._action_send_mail()
# Verify recipients of mail.message # Verify the followers of mail.message
message = self.test_record.message_ids[0] message = self.test_record.message_ids[0]
self.assertEqual(len(message.partner_ids), 2) self.assertEqual(len(message.partner_ids), 2)
self.assertIn(self.partner_follower1, message.partner_ids) self.assertIn(self.partner_follower1, message.partner_ids)
@ -62,13 +63,68 @@ class TestMailForward(TestMailComposer, HttpCase):
with RecordCapturer(self.env["mail.message"], message_domain) as capture: with RecordCapturer(self.env["mail.message"], message_domain) as capture:
with self.mock_mail_gateway(): with self.mock_mail_gateway():
composer._action_send_mail() composer._action_send_mail()
# Verify recipients of mail.message # Verify the followers of mail.message
forward_message = capture.records forward_message = capture.records
self.assertEqual(len(forward_message.partner_ids), 1) self.assertEqual(len(forward_message.partner_ids), 1)
self.assertNotIn(self.partner_follower1, forward_message.partner_ids) self.assertNotIn(self.partner_follower1, forward_message.partner_ids)
self.assertIn(self.partner_forward, forward_message.partner_ids) self.assertIn(self.partner_forward, forward_message.partner_ids)
self.assertIn("---------- Forwarded message ---------", forward_message.body) 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 = "<p>Hello</p>"
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 the followers 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 the followers 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): def test_02_mail_forward_tour(self):
self.test_record.message_post( self.test_record.message_post(
body="Hello World", message_type="comment", subtype_xmlid="mail.mt_comment" body="Hello World", message_type="comment", subtype_xmlid="mail.mt_comment"

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="view_ir_model_form" model="ir.ui.view">
<field name="name">view.ir.model.form</field>
<field name="model">ir.model</field>
<field name="inherit_id" ref="mail.model_form_view" />
<field name="arch" type="xml">
<xpath expr="//field[@name='is_mail_blacklist']" position="after">
<field
name="enable_forward_to"
groups="base.group_no_one"
invisible="transient or not is_mail_thread"
/>
</xpath>
</field>
</record>
</odoo>

View File

@ -1,11 +1,168 @@
# Copyright 2024 Tecnativa - Carlos Lopez # Copyright 2024 Tecnativa - Carlos Lopez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # 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): class MailComposeMessage(models.TransientModel):
_inherit = "mail.compose.message" _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),
("enable_forward_to", "=", 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 @api.model
def get_record_data(self, values): def get_record_data(self, values):
result = super().get_record_data(values) result = super().get_record_data(values)
@ -20,20 +177,6 @@ class MailComposeMessage(models.TransientModel):
return result return result
def _action_send_mail(self, auto_commit=False): def _action_send_mail(self, auto_commit=False):
# duplicate attachments from original message return super(
message_forwarded_id = self.env.context.get("message_forwarded_id") MailComposeMessage, self.with_context(forward_type=self.forward_type)
if message_forwarded_id: )._action_send_mail(auto_commit=auto_commit)
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)

View File

@ -7,8 +7,25 @@
<field name="priority" eval="100" /> <field name="priority" eval="100" />
<field name="inherit_id" ref="mail.email_compose_message_wizard_form" /> <field name="inherit_id" ref="mail.email_compose_message_wizard_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='email_from']" position="before">
<field
name="forward_type"
widget="radio"
options="{'horizontal': true}"
required="1"
/>
<field
name="forward_thread"
options="{'no_create': True}"
required="forward_type == 'another_thread'"
invisible="forward_type != 'another_thread'"
/>
</xpath>
<xpath expr="//field[@name='partner_ids']" position="attributes"> <xpath expr="//field[@name='partner_ids']" position="attributes">
<attribute name="required">1</attribute> <attribute name="required">forward_type == 'current_thread'</attribute>
</xpath>
<xpath expr="//label[@for='partner_ids']" position="attributes">
<attribute name="string">Followers to notify</attribute>
</xpath> </xpath>
<xpath expr="//span[@name='document_followers_text']" position="attributes"> <xpath expr="//span[@name='document_followers_text']" position="attributes">
<attribute name="invisible">1</attribute> <attribute name="invisible">1</attribute>