[ADD] mail_forward: new module to forward messages from the chatter

pull/1536/head
Carlos Lopez 2024-10-01 14:32:16 -05:00
parent cc0666843e
commit cd5e2421cd
22 changed files with 1186 additions and 0 deletions

View File

@ -0,0 +1,90 @@
====================
Mail Forward Message
====================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:ce6348512860de33703c2523bb1131aa2bb23a10374db4fb6f66383a7933134f
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsocial-lightgray.png?logo=github
:target: https://github.com/OCA/social/tree/15.0/mail_forward
:alt: OCA/social
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/social-15-0/social-15-0-mail_forward
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/social&target_branch=15.0
:alt: Try me on Runboat
|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.
**Table of contents**
.. contents::
:local:
Usage
=====
To use this module, follow these steps:
* Navigate to the chatter of any document.
* Hover the mouse over any message in the chatter (excluding internal 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.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/social/issues>`_.
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
`feedback <https://github.com/OCA/social/issues/new?body=module:%20mail_forward%0Aversion:%2015.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* Tecnativa
Contributors
~~~~~~~~~~~~
* `Tecnativa <https://www.tecnativa.com>`_:
* Carlos López
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
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.
This module is part of the `OCA/social <https://github.com/OCA/social/tree/15.0/mail_forward>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -0,0 +1,2 @@
from . import models
from . import wizards

View File

@ -0,0 +1,27 @@
# Copyright 2024 Tecnativa - Carlos Lopez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "Mail Forward Message",
"version": "15.0.1.0.0",
"summary": "Forward messages from the chatter of any document to other users.",
"author": "Tecnativa, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/social",
"depends": ["mail", "contacts"],
"data": [
"wizards/mail_compose_message_view.xml",
],
"assets": {
"web.assets_backend": [
"mail_forward/static/src/components/**/*.esm.js",
],
"web.assets_qweb": [
"mail_forward/static/src/components/*/*.xml",
],
"web.assets_tests": [
"mail_forward/static/tests/tours/**/*",
],
},
"installable": True,
"auto_install": False,
"license": "AGPL-3",
}

View File

@ -0,0 +1,83 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mail_forward
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.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"
"Last-Translator: \n"
"Language-Team: \n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 3.0.1\n"
#. module: mail_forward
#: code:addons/mail_forward/models/mail_message.py:0
#, python-format
msgid "---------- Forwarded message ---------"
msgstr "---------- Mensaje reenviado ---------"
#. module: mail_forward
#: code:addons/mail_forward/models/mail_message.py:0
#, python-format
msgid "Date"
msgstr "Fecha"
#. module: mail_forward
#: model:ir.model,name:mail_forward.model_mail_thread
msgid "Email Thread"
msgstr "Hilo de correos electrónicos"
#. 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"
#. module: mail_forward
#. openerp-web
#: code:addons/mail_forward/models/mail_message.py:0
#: code:addons/mail_forward/static/src/components/forward_message/forward_message.xml:0
#, python-format
msgid "Forward Message"
msgstr "Reenviar mensaje"
#. module: mail_forward
#: code:addons/mail_forward/models/mail_message.py:0
#, python-format
msgid "From"
msgstr "De"
#. module: mail_forward
#: code:addons/mail_forward/wizards/mail_compose_message.py:0
#, python-format
msgid "Fwd:"
msgstr ""
#. module: mail_forward
#: model:ir.model,name:mail_forward.model_mail_message
msgid "Message"
msgstr "Mensaje"
#. module: mail_forward
#: code:addons/mail_forward/wizards/mail_compose_message.py:0
#, python-format
msgid "Re:"
msgstr ""
#. module: mail_forward
#: code:addons/mail_forward/models/mail_message.py:0
#, python-format
msgid "Subject"
msgstr "Asunto"
#. module: mail_forward
#: code:addons/mail_forward/models/mail_message.py:0
#, python-format
msgid "To"
msgstr "Para"

View File

@ -0,0 +1,101 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mail_forward
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: mail_forward
#: code:addons/mail_forward/models/mail_message.py:0
#, python-format
msgid "---------- Forwarded message ---------"
msgstr ""
#. module: mail_forward
#: code:addons/mail_forward/models/mail_message.py:0
#, python-format
msgid "Date"
msgstr ""
#. module: mail_forward
#: model:ir.model,name:mail_forward.model_mail_thread
msgid "Email Thread"
msgstr ""
#. module: mail_forward
#: model:ir.model,name:mail_forward.model_mail_compose_message
msgid "Email composition wizard"
msgstr ""
#. module: mail_forward
#. openerp-web
#: code:addons/mail_forward/models/mail_message.py:0
#: 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
#, python-format
msgid "Forward Message"
msgstr ""
#. module: mail_forward
#. openerp-web
#: code:addons/mail_forward/static/src/components/forward_message/forward_message.xml:0
#, python-format
msgid "Forward Message Center"
msgstr ""
#. module: mail_forward
#. openerp-web
#: code:addons/mail_forward/static/src/components/forward_message/forward_message.xml:0
#, python-format
msgid "Forward Message Left"
msgstr ""
#. module: mail_forward
#. openerp-web
#: code:addons/mail_forward/static/src/components/forward_message/forward_message.xml:0
#, python-format
msgid "Forward Message Right"
msgstr ""
#. module: mail_forward
#: code:addons/mail_forward/models/mail_message.py:0
#, python-format
msgid "From"
msgstr ""
#. module: mail_forward
#: code:addons/mail_forward/wizards/mail_compose_message.py:0
#, python-format
msgid "Fwd:"
msgstr ""
#. module: mail_forward
#: model:ir.model,name:mail_forward.model_mail_message
msgid "Message"
msgstr ""
#. module: mail_forward
#: code:addons/mail_forward/wizards/mail_compose_message.py:0
#, python-format
msgid "Re:"
msgstr ""
#. module: mail_forward
#: code:addons/mail_forward/models/mail_message.py:0
#, python-format
msgid "Subject"
msgstr ""
#. module: mail_forward
#: code:addons/mail_forward/models/mail_message.py:0
#, python-format
msgid "To"
msgstr ""

View File

@ -0,0 +1,2 @@
from . import mail_message
from . import mail_thread

View File

@ -0,0 +1,57 @@
# Copyright 2024 Tecnativa - Carlos Lopez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import _, models
from odoo.tools import format_datetime
class MailMessage(models.Model):
_inherit = "mail.message"
def action_wizard_forward(self):
view = self.env.ref("mail_forward.mail_compose_message_forward_form")
action = self.env["ir.actions.actions"]._for_xml_id(
"mail.action_email_compose_message_wizard"
)
action["name"] = _("Forward Message")
action["view_mode"] = view.type
action["views"] = [(view.id, view.type)]
action["context"] = {
"default_model": self.model,
"default_res_id": 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,
"message_forwarded_id": self.id,
}
return action
def _build_message_body_for_forward(self):
partner_emails = [
partner.email_formatted
for partner in self.partner_ids
if partner.email_formatted
]
return """
<br/><br/><br/>
{str_forwarded_message}<br/>
{str_from}: {email_from}<br/>
{str_date}: {date}<br/>
{str_subject}: {subject}<br/>
{str_to}: {to}<br/>
<br/><br/>
{body}
""".format(
str_forwarded_message=_("---------- Forwarded message ---------"),
email_from=self.email_from,
date=format_datetime(self.env, self.date),
subject=self.subject,
to=", ".join(partner_emails),
str_date=_("Date"),
str_subject=_("Subject"),
str_from=_("From"),
str_to=_("To"),
body=self.body,
)

View File

@ -0,0 +1,19 @@
# Copyright 2024 Tecnativa - Carlos Lopez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import models
class MailThread(models.AbstractModel):
_inherit = "mail.thread"
def _notify_compute_recipients(self, message, msg_vals):
recipients_data = super()._notify_compute_recipients(message, msg_vals)
# only notify to explicit partners, remove others(followers).
if self.env.context.get("message_forwarded_id"):
current_partners_ids = message.partner_ids.ids
new_recipeints = []
for recipeint in recipients_data:
if recipeint["id"] in current_partners_ids:
new_recipeints.append(recipeint)
recipients_data = new_recipeints
return recipients_data

View File

@ -0,0 +1,2 @@
* `Tecnativa <https://www.tecnativa.com>`_:
* Carlos López

View File

@ -0,0 +1,2 @@
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.

View File

@ -0,0 +1,8 @@
To use this module, follow these steps:
* Navigate to the chatter of any document.
* Hover the mouse over any message in the chatter (excluding internal 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -0,0 +1,444 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Mail Forward Message</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="mail-forward-message">
<h1 class="title">Mail Forward Message</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:ce6348512860de33703c2523bb1131aa2bb23a10374db4fb6f66383a7933134f
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<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/15.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-15-0/social-15-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=15.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 document to other users,
adding them as followers of the document without notifying the current followers.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="toc-entry-1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<p>To use this module, follow these steps:</p>
<ul class="simple">
<li>Navigate to the chatter of any document.</li>
<li>Hover the mouse over any message in the chatter (excluding internal notes).</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>Select the users to forward the message to.</li>
<li>Click the Send Mail button to send the message to the selected users.</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<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.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/social/issues/new?body=module:%20mail_forward%0Aversion:%2015.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<ul class="simple">
<li>Tecnativa</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li><dl class="first docutils">
<dt><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:</dt>
<dd><ul class="first last">
<li>Carlos López</li>
</ul>
</dd>
</dl>
</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/social/tree/15.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>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,44 @@
/** @odoo-module **/
/* Copyright 2024 Tecnativa - Carlos Lopez
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
*/
import {registerMessagingComponent} from "@mail/utils/messaging_component";
const {Component} = owl;
export class ForwardMessage extends Component {
async onClickForwardMessage() {
const composer = this.props.message.originThread.composer;
const action = await this.env.services.rpc({
model: "mail.message",
method: "action_wizard_forward",
args: [[this.props.message.id]],
});
this.env.bus.trigger("do-action", {
action: action,
options: {
additional_context: {
active_id: this.props.message.id,
active_ids: [this.props.message.id],
active_model: "mail.message",
},
on_close: () => {
if (composer.exists()) {
composer._reset();
if (composer.activeThread) {
composer.activeThread.loadNewMessages();
composer.activeThread.refreshFollowers();
composer.activeThread.fetchAndUpdateSuggestedRecipients();
}
}
},
},
});
}
}
ForwardMessage.template = "mail_forward.ForwardMessage";
ForwardMessage.props = {
message: Object,
};
registerMessagingComponent(ForwardMessage);

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8" ?>
<templates xml:space="preserve">
<t t-name="mail_forward.ForwardMessage" owl="1">
<span
class="o_MessageActionList_action o_MessageActionList_actionForward fa-stack"
title="Forward Message"
role="button"
tabindex="0"
aria-label="Forward Message"
t-on-click="onClickForwardMessage"
>
<i
class="fa fa-lg fa-share fa-stack-1x"
style="margin-left:1px"
role="img"
aria-label="Forward Message Left"
/>
<i
class="fa fa-lg fa-share fa-inverse fa-stack-1x"
style="margin-left:-2px;"
role="img"
aria-label="Forward Message Center"
/>
<i
class="fa fa-lg fa-share fa-stack-1x"
style="margin-left:-3px"
role="img"
aria-label="Forward Message Right"
/>
</span>
</t>
</templates>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<templates xml:space="preserve">
<t t-inherit="mail.MessageActionList" t-inherit-mode="extension" owl="1">
<xpath expr="//span[@t-if='messageActionList.hasReplyIcon']" position="before">
<!-- Show the "Forward Message" button only on messages, not on notes. -->
<ForwardMessage
t-if="messageActionList.message.is_discussion &amp;&amp; !messageActionList.message.is_note"
message="messageActionList.message"
/>
</xpath>
</t>
</templates>

View File

@ -0,0 +1,116 @@
/** @odoo-module */
import tour from "web_tour.tour";
const contact_steps = [
...tour.stepUtils.goToAppSteps("contacts.menu_contacts", "Go to the Contacts."),
{
content: "Search Contact",
trigger: ".o_searchview_input",
run: "text Test",
},
{
trigger: ".o_menu_item",
content: "Validate search",
run: "click",
},
{
content: "Switch to list view",
trigger: ".o_list",
run: "click",
},
{
content: "Open contact",
trigger: ".o_list_table td[name='display_name']:contains('Test')",
},
];
tour.register(
"mail_forward.mail_forward_tour",
{
test: true,
url: "/web",
},
[
...contact_steps,
{
content: "Open Chat",
trigger: ".o_ChatterTopbar_buttonSendMessage",
run: "click",
},
{
content: "Write a message",
trigger: ".o_ComposerTextInput_textarea",
run: "text Hello World",
},
{
content: "Post a message",
trigger: ".o_Composer_buttonSend",
},
{
content: "Hover a message",
trigger: "div.o_Message.o-discussion",
run: "click",
},
{
content: "Forward a message",
trigger: ".o_MessageActionList_actionForward",
run: "click",
},
{
content: "Select a Forward",
trigger: ".o_field_widget[name=partner_ids] input",
extra_trigger: ".modal-dialog",
run: "text Forward",
},
{
content: "Valid Forward",
trigger: ".ui-menu-item a:contains(Forward)",
run: "click",
in_modal: false,
},
{
content: "Send mail",
trigger: "button[name=action_send_mail]",
run: "click",
},
{
content: "Check Mail Forward",
trigger:
".o_Message_prettyBody:contains(---------- Forwarded message ---------)",
},
]
);
tour.register(
"mail_forward.mail_note_not_forward_tour",
{
test: true,
url: "/web",
},
[
...contact_steps,
{
content: "Open Chat",
trigger: ".o_ChatterTopbar_buttonLogNote",
run: "click",
},
{
content: "Write a note",
trigger: ".o_ComposerTextInput_textarea",
run: "text This is a note",
},
{
content: "Post a note",
trigger: ".o_Composer_buttonSend",
},
{
content: "Hover a note",
trigger: "div.o_Message.o-not-discussion",
run: "click",
},
{
content: "Verify that the Forward button does not exist.",
trigger:
"div.o_Message.o-not-discussion:not(.o_MessageActionList_actionForward)",
},
]
);

View File

@ -0,0 +1 @@
from . import test_mail_forward

View File

@ -0,0 +1,77 @@
# Copyright 2024 Tecnativa - Carlos Lopez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo.tests import Form, RecordCapturer, tagged
from odoo.tests.common import HttpCase
from odoo.addons.mail.tests.test_mail_composer import TestMailComposer
@tagged("post_install", "-at_install")
class TestMailForward(TestMailComposer, HttpCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.partner_follower1 = cls.env["res.partner"].create(
{"name": "Follower1", "email": "follower1@example.com"}
)
cls.partner_follower2 = cls.env["res.partner"].create(
{"name": "Follower2", "email": "follower2@example.com"}
)
cls.partner_forward = cls.env["res.partner"].create(
{"name": "Forward", "email": "forward@example.com"}
)
def test_01_mail_forward(self):
"""
Send an email to followers
and forward it to another partner.
"""
ctx = {
"default_model": self.test_record._name,
"default_res_id": self.test_record.id,
}
composer_form = Form(self.env["mail.compose.message"].with_context(**ctx))
composer_form.body = "<p>Hello</p>"
composer_form.partner_ids.add(self.partner_follower1)
composer_form.partner_ids.add(self.partner_follower2)
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), 2)
self.assertIn(self.partner_follower1, message.partner_ids)
self.assertIn(self.partner_follower2, message.partner_ids)
self.assertNotIn(self.partner_forward, message.partner_ids)
self.assertNotIn("---------- Forwarded message ---------", message.body)
# Forward the email
# only the partner_forward should receive the email
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_forward)
composer = composer_form.save()
message_domain = [
("model", "=", self.test_record._name),
("res_id", "=", self.test_record.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(len(forward_message.partner_ids), 1)
self.assertNotIn(self.partner_follower1, forward_message.partner_ids)
self.assertIn(self.partner_forward, forward_message.partner_ids)
self.assertIn("---------- Forwarded message ---------", forward_message.body)
def test_02_mail_forward_tour(self):
self.start_tour("/web", "mail_forward.mail_forward_tour", login="admin")
def test_03_mail_note_not_forward_tour(self):
self.start_tour(
"/web", "mail_forward.mail_note_not_forward_tour", login="admin"
)

View File

@ -0,0 +1 @@
from . import mail_compose_message

View File

@ -0,0 +1,39 @@
# Copyright 2024 Tecnativa - Carlos Lopez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import Command, _, api, models
class MailComposeMessage(models.TransientModel):
_inherit = "mail.compose.message"
@api.model
def get_record_data(self, values):
result = super().get_record_data(values)
re_prefix = _("Re:")
fwd_prefix = _("Fwd:")
if self.env.context.get("message_forwarded_id"):
# remove 'Re: ' prefixes and add 'Fwd:' prefix to the subject
subject = result.get("subject")
if subject and subject.startswith(re_prefix):
subject = "%s %s" % (fwd_prefix, subject[4:])
result["subject"] = subject
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)

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="mail_compose_message_forward_form">
<field name="name">mail.compose.message.form.forward</field>
<field name="model">mail.compose.message</field>
<field name="mode">primary</field>
<field name="priority" eval="100" />
<field name="inherit_id" ref="mail.email_compose_message_wizard_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_ids']" position="attributes">
<attribute name="required">1</attribute>
</xpath>
<xpath expr="//span[@name='document_followers_text']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='template_id']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath
expr="//button[@name='action_save_as_template']"
position="attributes"
>
<attribute name="invisible">1</attribute>
</xpath>
</field>
</record>
</odoo>