From d22059335ade1192f992320a90a895195f2fcff3 Mon Sep 17 00:00:00 2001 From: bosd Date: Sun, 20 Apr 2025 00:34:50 +0200 Subject: [PATCH 1/2] mail_brand_templates --- mail_brand_templates/README.rst | 147 ++++++ mail_brand_templates/__init__.py | 2 + mail_brand_templates/__manifest__.py | 20 + mail_brand_templates/models/__init__.py | 1 + mail_brand_templates/models/mail_template.py | 10 + mail_brand_templates/readme/CONFIGURE.rst | 21 + mail_brand_templates/readme/CONTEXT.rst | 3 + mail_brand_templates/readme/CONTRIBUTORS.rst | 1 + mail_brand_templates/readme/CREDITS.rst | 0 mail_brand_templates/readme/DESCRIPTION.rst | 8 + mail_brand_templates/readme/ROADMAP.rst | 1 + mail_brand_templates/readme/USAGE.rst | 15 + .../security/mail_template_security.xml | 11 + .../static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 481 ++++++++++++++++++ mail_brand_templates/tests/__init__.py | 1 + .../tests/test_mail_template.py | 63 +++ mail_brand_templates/views/mail_template.xml | 23 + mail_brand_templates/wizard/__init__.py | 0 .../wizard/mail_compose_message_view.xml | 18 + 20 files changed, 826 insertions(+) create mode 100644 mail_brand_templates/README.rst create mode 100644 mail_brand_templates/__init__.py create mode 100644 mail_brand_templates/__manifest__.py create mode 100644 mail_brand_templates/models/__init__.py create mode 100644 mail_brand_templates/models/mail_template.py create mode 100644 mail_brand_templates/readme/CONFIGURE.rst create mode 100644 mail_brand_templates/readme/CONTEXT.rst create mode 100644 mail_brand_templates/readme/CONTRIBUTORS.rst create mode 100644 mail_brand_templates/readme/CREDITS.rst create mode 100644 mail_brand_templates/readme/DESCRIPTION.rst create mode 100644 mail_brand_templates/readme/ROADMAP.rst create mode 100644 mail_brand_templates/readme/USAGE.rst create mode 100644 mail_brand_templates/security/mail_template_security.xml create mode 100644 mail_brand_templates/static/description/icon.png create mode 100644 mail_brand_templates/static/description/index.html create mode 100644 mail_brand_templates/tests/__init__.py create mode 100644 mail_brand_templates/tests/test_mail_template.py create mode 100644 mail_brand_templates/views/mail_template.xml create mode 100644 mail_brand_templates/wizard/__init__.py create mode 100644 mail_brand_templates/wizard/mail_compose_message_view.xml diff --git a/mail_brand_templates/README.rst b/mail_brand_templates/README.rst new file mode 100644 index 000000000..30cd872da --- /dev/null +++ b/mail_brand_templates/README.rst @@ -0,0 +1,147 @@ +============================== +Brand Specific Email Templates +============================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:611297e47ca2d8d03a5f199362c393956c1533eafe469a918d6600dc1f8cfd3e + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fbrand-lightgray.png?logo=github + :target: https://github.com/OCA/brand/tree/15.0/mail_brand_templates + :alt: OCA/brand +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/brand-15-0/brand-15-0-mail_brand_templates + :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/brand&target_branch=15.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module enhances Odoo's email communication by introducing brand-aware email template management. + +**Key Features:** + +* **Brand Association with Email Templates:** Provides the functionality to assign a specific brand to individual email templates within Odoo. This ensures that each template is clearly linked to a particular brand identity. +* **Contextual Email Template Filtering:** When sending emails from a specific document (e.g., a Sale Order), the module intelligently filters the available email templates, allowing users to select only those templates that are associated with the same brand as the originating document (if a brand is set on that document). + +With this module, you can streamline your email creation process by ensuring that users can easily select and utilize email templates that are consistent with the brand context of their communication. + +**Table of contents** + +.. contents:: + :local: + +Use Cases / Context +=================== + +Organizations operating with multiple brands often struggle to maintain consistent and accurate brand representation across all customer communications, particularly in automated and transactional emails. + +There is a need for a system that can seamlessly apply the correct branding – including logos, sender details, and potentially communication styles – to emails based on the specific brand context, ensuring a unified and professional customer experience. Furthermore, restricting the use of email templates to those aligned with the brand of the originating communication ensures brand compliance and reduces the risk of sending out off-brand or irrelevant content. + +Configuration +============= + + +**Steps to Set a Brand for an Email Template:** + + +1. **Navigate to Email Templates:** + * Go to **Settings > Technical > Email > Templates**. + +2. **Select an Existing Template or Create a New One:** + * **To modify an existing template:** Find the email template you want to brand in the list and click on it to open its form view. + * **To create a new template:** Click on the **Create** button to define a new email template. + +3. **Locate the "Brand" Field:** + * In the email template's form view, you will find a field labeled **Brand**. This field is introduced by this module. + +4. **Assign a Brand:** + * Click on the dropdown arrow next to the **Brand** field. + * Select the specific brand that you want to associate with this email template from the list. + * If the desired brand is not listed, you may need to create it first. + +5. **Save the Email Template:** + * Once you have selected the brand, click the **Save** button to save the changes to the email template. + +Usage +===== + + +**Using Brand-Specific Templates:** + +* When sending emails from a document that has a brand associated with it (e.g., a Sale Order with a 'Brand A' set), and you choose to use a pre-defined template, the module will filter the available templates. You will only see templates that are either not associated with any brand or are associated with the same brand ('Brand A' in this example). +* If you manually select a brand in the "Compose Email" wizard, the same filtering logic will apply when choosing an email template. + +**Example:** + +Let's say you have two brands defined: "Brand A" and "Brand B". + +* You create an email template for sending order confirmations and set its **Brand** to "Brand A". +* When a user sends an order confirmation email from a Sale Order that has "Brand A" set, this specific order confirmation template will be available for selection. +* If the Sale Order has "Brand B" set, the "Brand A" order confirmation template will be filtered out, and only templates associated with "Brand B" or no brand will be available. + +By associating brands with your email templates, you can ensure that your communication is always consistent with the relevant brand identity. + +Known issues / Roadmap +====================== + +- + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* bosd + +Contributors +~~~~~~~~~~~~ + +* Bosd + +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. + +.. |maintainer-bosd| image:: https://github.com/bosd.png?size=40px + :target: https://github.com/bosd + :alt: bosd + +Current `maintainer `__: + +|maintainer-bosd| + +This module is part of the `OCA/brand `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/mail_brand_templates/__init__.py b/mail_brand_templates/__init__.py new file mode 100644 index 000000000..9b4296142 --- /dev/null +++ b/mail_brand_templates/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizard diff --git a/mail_brand_templates/__manifest__.py b/mail_brand_templates/__manifest__.py new file mode 100644 index 000000000..5b660279b --- /dev/null +++ b/mail_brand_templates/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2025 bosd +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Brand Specific Email Templates", + "summary": """ + Allows to define email templates specific to a brand. + """, + "license": "AGPL-3", + "author": "Odoo Community Association (OCA), bosd", + "website": "https://github.com/OCA/brand", + "version": "15.0.1.0.0", + "depends": ["mail_brand", "brand"], + "data": [ + "wizard/mail_compose_message_view.xml", + "security/mail_template_security.xml", + "views/mail_template.xml", + ], + "maintainers": ["bosd"], +} diff --git a/mail_brand_templates/models/__init__.py b/mail_brand_templates/models/__init__.py new file mode 100644 index 000000000..44e83956e --- /dev/null +++ b/mail_brand_templates/models/__init__.py @@ -0,0 +1 @@ +from . import mail_template diff --git a/mail_brand_templates/models/mail_template.py b/mail_brand_templates/models/mail_template.py new file mode 100644 index 000000000..b0a53d885 --- /dev/null +++ b/mail_brand_templates/models/mail_template.py @@ -0,0 +1,10 @@ +# Copyright (C) 2025 Bosd +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class MailTemplateExt(models.Model): + _inherit = "mail.template" + + brand_id = fields.Many2one("res.brand", "Brand") diff --git a/mail_brand_templates/readme/CONFIGURE.rst b/mail_brand_templates/readme/CONFIGURE.rst new file mode 100644 index 000000000..564cc7b58 --- /dev/null +++ b/mail_brand_templates/readme/CONFIGURE.rst @@ -0,0 +1,21 @@ + +**Steps to Set a Brand for an Email Template:** + + +1. **Navigate to Email Templates:** + * Go to **Settings > Technical > Email > Templates**. + +2. **Select an Existing Template or Create a New One:** + * **To modify an existing template:** Find the email template you want to brand in the list and click on it to open its form view. + * **To create a new template:** Click on the **Create** button to define a new email template. + +3. **Locate the "Brand" Field:** + * In the email template's form view, you will find a field labeled **Brand**. This field is introduced by this module. + +4. **Assign a Brand:** + * Click on the dropdown arrow next to the **Brand** field. + * Select the specific brand that you want to associate with this email template from the list. + * If the desired brand is not listed, you may need to create it first. + +5. **Save the Email Template:** + * Once you have selected the brand, click the **Save** button to save the changes to the email template. diff --git a/mail_brand_templates/readme/CONTEXT.rst b/mail_brand_templates/readme/CONTEXT.rst new file mode 100644 index 000000000..28b6b7d35 --- /dev/null +++ b/mail_brand_templates/readme/CONTEXT.rst @@ -0,0 +1,3 @@ +Organizations operating with multiple brands often struggle to maintain consistent and accurate brand representation across all customer communications, particularly in automated and transactional emails. + +There is a need for a system that can seamlessly apply the correct branding – including logos, sender details, and potentially communication styles – to emails based on the specific brand context, ensuring a unified and professional customer experience. Furthermore, restricting the use of email templates to those aligned with the brand of the originating communication ensures brand compliance and reduces the risk of sending out off-brand or irrelevant content. diff --git a/mail_brand_templates/readme/CONTRIBUTORS.rst b/mail_brand_templates/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..4cc86b7f6 --- /dev/null +++ b/mail_brand_templates/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Bosd diff --git a/mail_brand_templates/readme/CREDITS.rst b/mail_brand_templates/readme/CREDITS.rst new file mode 100644 index 000000000..e69de29bb diff --git a/mail_brand_templates/readme/DESCRIPTION.rst b/mail_brand_templates/readme/DESCRIPTION.rst new file mode 100644 index 000000000..e948e9f0a --- /dev/null +++ b/mail_brand_templates/readme/DESCRIPTION.rst @@ -0,0 +1,8 @@ +This module enhances Odoo's email communication by introducing brand-aware email template management. + +**Key Features:** + +* **Brand Association with Email Templates:** Provides the functionality to assign a specific brand to individual email templates within Odoo. This ensures that each template is clearly linked to a particular brand identity. +* **Contextual Email Template Filtering:** When sending emails from a specific document (e.g., a Sale Order), the module intelligently filters the available email templates, allowing users to select only those templates that are associated with the same brand as the originating document (if a brand is set on that document). + +With this module, you can streamline your email creation process by ensuring that users can easily select and utilize email templates that are consistent with the brand context of their communication. diff --git a/mail_brand_templates/readme/ROADMAP.rst b/mail_brand_templates/readme/ROADMAP.rst new file mode 100644 index 000000000..39cdd0ded --- /dev/null +++ b/mail_brand_templates/readme/ROADMAP.rst @@ -0,0 +1 @@ +- diff --git a/mail_brand_templates/readme/USAGE.rst b/mail_brand_templates/readme/USAGE.rst new file mode 100644 index 000000000..beab4c4f6 --- /dev/null +++ b/mail_brand_templates/readme/USAGE.rst @@ -0,0 +1,15 @@ + +**Using Brand-Specific Templates:** + +* When sending emails from a document that has a brand associated with it (e.g., a Sale Order with a 'Brand A' set), and you choose to use a pre-defined template, the module will filter the available templates. You will only see templates that are either not associated with any brand or are associated with the same brand ('Brand A' in this example). +* If you manually select a brand in the "Compose Email" wizard, the same filtering logic will apply when choosing an email template. + +**Example:** + +Let's say you have two brands defined: "Brand A" and "Brand B". + +* You create an email template for sending order confirmations and set its **Brand** to "Brand A". +* When a user sends an order confirmation email from a Sale Order that has "Brand A" set, this specific order confirmation template will be available for selection. +* If the Sale Order has "Brand B" set, the "Brand A" order confirmation template will be filtered out, and only templates associated with "Brand B" or no brand will be available. + +By associating brands with your email templates, you can ensure that your communication is always consistent with the relevant brand identity. diff --git a/mail_brand_templates/security/mail_template_security.xml b/mail_brand_templates/security/mail_template_security.xml new file mode 100644 index 000000000..bb607901f --- /dev/null +++ b/mail_brand_templates/security/mail_template_security.xml @@ -0,0 +1,11 @@ + + + + Brand Specific Mail Templates + + + + + + + diff --git a/mail_brand_templates/static/description/icon.png b/mail_brand_templates/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/mail_brand_templates/static/description/index.html b/mail_brand_templates/static/description/index.html new file mode 100644 index 000000000..87e47e4fb --- /dev/null +++ b/mail_brand_templates/static/description/index.html @@ -0,0 +1,481 @@ + + + + + +Brand Specific Email Templates + + + +
+

Brand Specific Email Templates

+ + +

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

+

This module enhances Odoo’s email communication by introducing brand-aware email template management.

+

Key Features:

+
    +
  • Brand Association with Email Templates: Provides the functionality to assign a specific brand to individual email templates within Odoo. This ensures that each template is clearly linked to a particular brand identity.
  • +
  • Contextual Email Template Filtering: When sending emails from a specific document (e.g., a Sale Order), the module intelligently filters the available email templates, allowing users to select only those templates that are associated with the same brand as the originating document (if a brand is set on that document).
  • +
+

With this module, you can streamline your email creation process by ensuring that users can easily select and utilize email templates that are consistent with the brand context of their communication.

+

Table of contents

+ +
+

Use Cases / Context

+

Organizations operating with multiple brands often struggle to maintain consistent and accurate brand representation across all customer communications, particularly in automated and transactional emails.

+

There is a need for a system that can seamlessly apply the correct branding – including logos, sender details, and potentially communication styles – to emails based on the specific brand context, ensuring a unified and professional customer experience. Furthermore, restricting the use of email templates to those aligned with the brand of the originating communication ensures brand compliance and reduces the risk of sending out off-brand or irrelevant content.

+
+
+

Configuration

+

Steps to Set a Brand for an Email Template:

+
    +
  1. Navigate to Email Templates: +* Go to Settings > Technical > Email > Templates.
  2. +
  3. Select an Existing Template or Create a New One: +* To modify an existing template: Find the email template you want to brand in the list and click on it to open its form view. +* To create a new template: Click on the Create button to define a new email template.
  4. +
  5. Locate the “Brand” Field: +* In the email template’s form view, you will find a field labeled Brand. This field is introduced by this module.
  6. +
  7. Assign a Brand: +* Click on the dropdown arrow next to the Brand field. +* Select the specific brand that you want to associate with this email template from the list. +* If the desired brand is not listed, you may need to create it first.
  8. +
  9. Save the Email Template: +* Once you have selected the brand, click the Save button to save the changes to the email template.
  10. +
+
+
+

Usage

+

Using Brand-Specific Templates:

+
    +
  • When sending emails from a document that has a brand associated with it (e.g., a Sale Order with a ‘Brand A’ set), and you choose to use a pre-defined template, the module will filter the available templates. You will only see templates that are either not associated with any brand or are associated with the same brand (‘Brand A’ in this example).
  • +
  • If you manually select a brand in the “Compose Email” wizard, the same filtering logic will apply when choosing an email template.
  • +
+

Example:

+

Let’s say you have two brands defined: “Brand A” and “Brand B”.

+
    +
  • You create an email template for sending order confirmations and set its Brand to “Brand A”.
  • +
  • When a user sends an order confirmation email from a Sale Order that has “Brand A” set, this specific order confirmation template will be available for selection.
  • +
  • If the Sale Order has “Brand B” set, the “Brand A” order confirmation template will be filtered out, and only templates associated with “Brand B” or no brand will be available.
  • +
+

By associating brands with your email templates, you can ensure that your communication is always consistent with the relevant brand identity.

+
+ +
+

Bug Tracker

+

Bugs are tracked on GitHub 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.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • bosd
  • +
+
+
+

Contributors

+
    +
  • Bosd
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

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:

+

bosd

+

This module is part of the OCA/brand project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/mail_brand_templates/tests/__init__.py b/mail_brand_templates/tests/__init__.py new file mode 100644 index 000000000..b3ad65b46 --- /dev/null +++ b/mail_brand_templates/tests/__init__.py @@ -0,0 +1 @@ +from . import test_mail_template diff --git a/mail_brand_templates/tests/test_mail_template.py b/mail_brand_templates/tests/test_mail_template.py new file mode 100644 index 000000000..282492f91 --- /dev/null +++ b/mail_brand_templates/tests/test_mail_template.py @@ -0,0 +1,63 @@ +from odoo.tests.common import TransactionCase + + +class TestMailTemplate(TransactionCase): + @classmethod + def setUpClass(cls): + super(TestMailTemplate, cls).setUpClass() + cls.brand_a = cls.env["res.brand"].create( + {"partner_id": cls.env["res.partner"].create({"name": "Brand A"}).id} + ) + cls.brand_b = cls.env["res.brand"].create( + {"partner_id": cls.env["res.partner"].create({"name": "Brand B"}).id} + ) + cls.mail_template = cls.env["mail.template"] + cls.ir_model = cls.env["ir.model"] + cls.partner_model_id = cls.ir_model.search( + [("model", "=", "res.partner")], limit=1 + ).id + + def test_brand_id_on_template_creation(self): + template = self.mail_template.create( + { + "name": "Test Template A", + "subject": "Test Subject", + "body_html": "

Test Body

", + "brand_id": self.brand_a.id, + "model_id": self.partner_model_id, + } + ) + self.assertEqual( + template.brand_id, self.brand_a, "Template should have the assigned brand" + ) + + def test_brand_id_on_template_read(self): + template = self.mail_template.create( + { + "name": "Test Template B", + "subject": "Test Subject", + "body_html": "

Test Body

", + "brand_id": self.brand_b.id, + "model_id": self.partner_model_id, + } + ) + read_template = self.mail_template.browse(template.id) + self.assertEqual( + read_template.brand_id, + self.brand_b, + "Read template should retain the assigned brand", + ) + + def test_brand_id_on_template_write(self): + template = self.mail_template.create( + { + "name": "Test Template C", + "subject": "Test Subject", + "body_html": "

Test Body

", + "model_id": self.partner_model_id, + } + ) + template.write({"brand_id": self.brand_a.id}) + self.assertEqual( + template.brand_id, self.brand_a, "Template should have the updated brand" + ) diff --git a/mail_brand_templates/views/mail_template.xml b/mail_brand_templates/views/mail_template.xml new file mode 100644 index 000000000..7895c0eab --- /dev/null +++ b/mail_brand_templates/views/mail_template.xml @@ -0,0 +1,23 @@ + + + + mail.template.form.mail + mail.template + + + + + + + + + mail.template.tree.mail + mail.template + + + + + + + + diff --git a/mail_brand_templates/wizard/__init__.py b/mail_brand_templates/wizard/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/mail_brand_templates/wizard/mail_compose_message_view.xml b/mail_brand_templates/wizard/mail_compose_message_view.xml new file mode 100644 index 000000000..12704979b --- /dev/null +++ b/mail_brand_templates/wizard/mail_compose_message_view.xml @@ -0,0 +1,18 @@ + + + + mail.compose.message.form.brand.domain + mail.compose.message + + + + + [('model', '=', model), + '|', + ('brand_id', '=', brand_id), + ('brand_id', '=', False)] + + + + + From c6641457a26bd50a279615f944515465fa0966f7 Mon Sep 17 00:00:00 2001 From: bosd Date: Thu, 11 Sep 2025 11:42:28 +0200 Subject: [PATCH 2/2] [DO NOT MERGE] --- test-requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 test-requirements.txt diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 000000000..7efb55a24 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1 @@ +odoo-addon-mail-brand @ git+https://github.com/OCA/brand.git@refs/pull/247/head#subdirectory=mail_brand