Merge PR #1548 into 17.0

Signed-off-by pedrobaeza
pull/1578/head
OCA-git-bot 2025-02-03 10:30:33 +00:00
commit dd801df48e
7 changed files with 107 additions and 44 deletions

View File

@ -39,28 +39,32 @@ the notification emails sent by Odoo
Configuration Configuration
============= =============
- Activate access to **Technical Features** (debug mode). - Activate access to **Technical Features** (debug mode).
- Go to **Settings > Technical > Email > Subject Replacement Templates** - Go to **Settings > Technical > Email > Subject Replacement
Templates**
- Create a new template. - Create a new template.
- The field **Model** specifies the model to which the subject - The field **Model** specifies the model to which the subject
template should apply in the notification emails sent by Odoo. template should apply in the notification emails sent by Odoo.
- The field **Subject Template** accepts - The field **Subject Template** accepts
`Jinja <https://jinja.palletsprojects.com/en/2.11.x/>`__ `expressions <https://www.odoo.com/documentation/17.0/applications/general/companies/email_template.html#dynamic-placeholders>`__.
expressions. - The field **Subject to replace** accepts
- The field **Replace** specifies if the template should replace `expressions <https://www.odoo.com/documentation/17.0/applications/general/companies/email_template.html#dynamic-placeholders>`__
existing content or append to it. - The field **Replace** specifies if the template should replace
existing content or append to it.
- The field **Partial Replacement** specifies if the template
should parcial replace existing content.
Usage Usage
===== =====
To use this module, you need to: To use this module, you need to:
- Open the chatter in Odoo (e.g. Open an Invoice). - Open the chatter in Odoo (e.g. Open an Invoice).
- Send a message. - Send a message.
- Observe the rendered Subject template. - Observe the rendered Subject template.
Bug Tracker Bug Tracker
=========== ===========
@ -83,20 +87,20 @@ Authors
Contributors Contributors
------------ ------------
- Tecnativa <https://www.tecnativa.com> - Tecnativa <https://www.tecnativa.com>
- Pedro M. Baeza - Pedro M. Baeza
- João Marques - João Marques
- Carlos Roca - Carlos Roca
- Víctor Martínez - Víctor Martínez
- Versada <https://versada.eu> - Versada <https://versada.eu>
- Naglis Jonaitis - Naglis Jonaitis
- Moduon <https://www.moduon.team> - Moduon <https://www.moduon.team>
- Eduardo de Miguel - Eduardo de Miguel
Maintainers Maintainers
----------- -----------

View File

@ -21,6 +21,10 @@ class MailMessageCustomSubject(models.Model):
string="Applied Subtypes", string="Applied Subtypes",
required=True, required=True,
) )
subject_to_replace = fields.Char(
help="The text that will be replaced. You can use placeholders."
" E.g.: {{ object.company_id.name }}"
)
subject_template = fields.Char( subject_template = fields.Char(
required=True, required=True,
translate=True, translate=True,
@ -31,8 +35,9 @@ class MailMessageCustomSubject(models.Model):
("append_before", "Append Before"), ("append_before", "Append Before"),
("append_after", "Append After"), ("append_after", "Append After"),
("replace", "Replace"), ("replace", "Replace"),
("inside_replace", "Partial Replacement"),
], ],
default="replace", default="replace",
help="Whether to replace, append at beggining or append at end to other" help="Whether to replace completely, partially, append at beginning or append"
" templates that apply to a given context", " at end to other templates that apply to a given context",
) )

View File

@ -1,10 +1,14 @@
# Copyright 2020-2021 Tecnativa - João Marques # Copyright 2020-2021 Tecnativa - João Marques
# Copyright 2021 Tecnativa - Pedro M. Baeza # Copyright 2021 Tecnativa - Pedro M. Baeza
# Copyright 2022 Moduon - Eduardo de Miguel # Copyright 2022 Moduon - Eduardo de Miguel
# Copyright 2025 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import logging
from odoo import api, models from odoo import api, models
_logger = logging.getLogger(__name__)
class MailThread(models.AbstractModel): class MailThread(models.AbstractModel):
_inherit = "mail.thread" _inherit = "mail.thread"
@ -35,15 +39,17 @@ class MailThread(models.AbstractModel):
if not subtype_id: if not subtype_id:
subtype_id = self.env["ir.model.data"]._xmlid_to_res_id("mail.mt_note") subtype_id = self.env["ir.model.data"]._xmlid_to_res_id("mail.mt_note")
if subtype_id: if subtype_id:
domain = [
("model_id.model", "=", self._name),
("subtype_ids", "=", subtype_id),
]
if subject:
# If it already had a defined subject, we must respect it
domain += [("position", "!=", "replace")]
custom_subjects = ( custom_subjects = (
self.env["mail.message.custom.subject"] self.env["mail.message.custom.subject"]
.sudo() .sudo()
.search( .search(domain)
[
("model_id.model", "=", self._name),
("subtype_ids", "=", subtype_id),
]
)
.sudo(False) .sudo(False)
) )
if not subject: if not subject:
@ -66,8 +72,25 @@ class MailThread(models.AbstractModel):
subject = rendered_subject_template + subject subject = rendered_subject_template + subject
elif template.position == "append_after": elif template.position == "append_after":
subject += rendered_subject_template subject += rendered_subject_template
elif template.position == "inside_replace":
rendered_subject_to_replace = self.env[
"mail.template"
]._render_template(
template_src=template.subject_to_replace,
model=self._name,
res_ids=[self.id],
)[self.id]
if rendered_subject_to_replace:
# To avoid empty string replacements
subject = subject.replace(
rendered_subject_to_replace,
rendered_subject_template,
)
except Exception: except Exception:
rendered_subject_template = False _logger.warning(
f"There is an error with {self.display_name} in the mail "
f"message custom subject {template.name}"
)
return super().message_post( return super().message_post(
body=body, body=body,
subject=subject, subject=subject,

View File

@ -8,6 +8,10 @@
> - The field **Model** specifies the model to which the subject > - The field **Model** specifies the model to which the subject
> template should apply in the notification emails sent by Odoo. > template should apply in the notification emails sent by Odoo.
> - The field **Subject Template** accepts > - The field **Subject Template** accepts
> [Jinja](https://jinja.palletsprojects.com/en/2.11.x/) expressions. > [expressions](https://www.odoo.com/documentation/17.0/applications/general/companies/email_template.html#dynamic-placeholders).
> - The field **Subject to replace** accepts
> [expressions](https://www.odoo.com/documentation/17.0/applications/general/companies/email_template.html#dynamic-placeholders)
> - The field **Replace** specifies if the template should replace > - The field **Replace** specifies if the template should replace
> existing content or append to it. > existing content or append to it.
> - The field **Partial Replacement** specifies if the template should
> parcial replace existing content.

View File

@ -8,11 +8,10 @@
/* /*
:Author: David Goodger (goodger@python.org) :Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Copyright: This stylesheet has been placed in the public domain. :Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils. 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 See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet. customize this style sheet.
@ -275,7 +274,7 @@ pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ; margin-left: 2em ;
margin-right: 2em } margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */ pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee } pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 } pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
@ -301,7 +300,7 @@ span.option {
span.pre { span.pre {
white-space: pre } white-space: pre }
span.problematic, pre.problematic { span.problematic {
color: red } color: red }
span.section-subtitle { span.section-subtitle {
@ -391,7 +390,8 @@ the notification emails sent by Odoo</p>
<ul> <ul>
<li><p class="first">Activate access to <strong>Technical Features</strong> (debug mode).</p> <li><p class="first">Activate access to <strong>Technical Features</strong> (debug mode).</p>
</li> </li>
<li><p class="first">Go to <strong>Settings &gt; Technical &gt; Email &gt; Subject Replacement Templates</strong></p> <li><p class="first">Go to <strong>Settings &gt; Technical &gt; Email &gt; Subject Replacement
Templates</strong></p>
</li> </li>
<li><p class="first">Create a new template.</p> <li><p class="first">Create a new template.</p>
<blockquote> <blockquote>
@ -399,10 +399,13 @@ the notification emails sent by Odoo</p>
<li>The field <strong>Model</strong> specifies the model to which the subject <li>The field <strong>Model</strong> specifies the model to which the subject
template should apply in the notification emails sent by Odoo.</li> template should apply in the notification emails sent by Odoo.</li>
<li>The field <strong>Subject Template</strong> accepts <li>The field <strong>Subject Template</strong> accepts
<a class="reference external" href="https://jinja.palletsprojects.com/en/2.11.x/">Jinja</a> <a class="reference external" href="https://www.odoo.com/documentation/17.0/applications/general/companies/email_template.html#dynamic-placeholders">expressions</a>.</li>
expressions.</li> <li>The field <strong>Subject to replace</strong> accepts
<a class="reference external" href="https://www.odoo.com/documentation/17.0/applications/general/companies/email_template.html#dynamic-placeholders">expressions</a></li>
<li>The field <strong>Replace</strong> specifies if the template should replace <li>The field <strong>Replace</strong> specifies if the template should replace
existing content or append to it.</li> existing content or append to it.</li>
<li>The field <strong>Partial Replacement</strong> specifies if the template
should parcial replace existing content.</li>
</ul> </ul>
</blockquote> </blockquote>
</li> </li>
@ -461,9 +464,7 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
<div class="section" id="maintainers"> <div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-7">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" /></a>
<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 <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>

View File

@ -48,12 +48,33 @@ class TestMailNotificationCustomSubject(BaseCommon):
# Get message and check subject # Get message and check subject
self.assertEqual(mail_message_2.subject, "Test partner 2 and something more") self.assertEqual(mail_message_2.subject, "Test partner 2 and something more")
# Explicit subject should also be overwritten # Explicit subject should not also overwritten
mail_message_3 = self.partner_2.message_post( mail_message_3 = self.partner_2.message_post(
body="Test", subtype_xmlid="mail.mt_comment", subject="Test" body="Test", subtype_xmlid="mail.mt_comment", subject="Test"
) )
# Get message and check subject # Get message and check subject
self.assertEqual(mail_message_3.subject, "Test partner 2 and something more") self.assertEqual(mail_message_3.subject, "Test")
def test_email_subject_template_inside_replace(self):
with self.with_user("boss"):
self.env["mail.message.custom.subject"].create(
{
"name": "Test template",
"model_id": self.env.ref("base.model_res_partner").id,
"subtype_ids": [(6, 0, [self.env.ref("mail.mt_comment").id])],
"subject_to_replace": "{{object.company_id.name}}",
"subject_template": "CLN",
"position": "inside_replace",
}
)
self.partner_1.company_id = self.env.company
self.partner_1.company_id.name = "COMPANY_LONG_NAME"
mail_message_1 = self.partner_1.message_post(
subject="COMPANY_LONG_NAME: Custom",
body="Test",
subtype_xmlid="mail.mt_comment",
)
self.assertEqual(mail_message_1.subject, "CLN: Custom")
def test_email_subject_template_normal(self): def test_email_subject_template_normal(self):
with self.with_user("boss"): with self.with_user("boss"):

View File

@ -11,6 +11,11 @@
<h1 name="name"><field name="name" /></h1> <h1 name="name"><field name="name" /></h1>
</div> </div>
<group> <group>
<field
name="subject_to_replace"
invisible="position!='inside_replace'"
required="position=='inside_replace'"
/>
<field <field
name="subject_template" name="subject_template"
placeholder="Subject (placeholders may be used here)" placeholder="Subject (placeholders may be used here)"