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

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/social Translate me on Weblate Try me on Runboat

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 @@

    Usage

    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 @@

Maintainers

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

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