diff --git a/outgoing_email_by_model/README.rst b/outgoing_email_by_model/README.rst new file mode 100644 index 0000000000..2040a315d4 --- /dev/null +++ b/outgoing_email_by_model/README.rst @@ -0,0 +1,94 @@ +======================= +Outgoing Email by Model +======================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:0de5a293f68d4c9a7b9b358dbbd1c678a8278e1fadcf1b0876b521d4dba266dc + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/16.0/outgoing_email_by_model + :alt: OCA/social +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/social-16-0/social-16-0-outgoing_email_by_model + :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=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Allow to select an outgoing mail parameters per model, such as email_from, or mail_server_id. + +To make it work, the model must inherit `mail.thread`. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +If you want to use a specific outgoing mail for a model, populate the following fields in the model record (Settings > Technical > Models) accordingly: + +* Outgoing Mailserver: Set an outgoing mail server. This will be used as the forced outgoing mail server for the model. +* Outgoing Email: Set an email address. This will be used as the outgoing email for the model. + +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 +~~~~~~~ + +* Camptocamp + +Contributors +~~~~~~~~~~~~ + +* Emilie SOUTIRAS + +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-mmequignon| image:: https://github.com/mmequignon.png?size=40px + :target: https://github.com/mmequignon + :alt: mmequignon + +Current `maintainer `__: + +|maintainer-mmequignon| + +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/outgoing_email_by_model/__init__.py b/outgoing_email_by_model/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/outgoing_email_by_model/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/outgoing_email_by_model/__manifest__.py b/outgoing_email_by_model/__manifest__.py new file mode 100644 index 0000000000..4c67bad5c0 --- /dev/null +++ b/outgoing_email_by_model/__manifest__.py @@ -0,0 +1,24 @@ +# Copyright (c) 2024 Groupe Voltaire +# @author Emilie SOUTIRAS +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Outgoing Email by Model", + "version": "15.0.1.0.0", + "category": "Social", + "website": "https://github.com/OCA/social", + "author": "Camptocamp, Odoo Community Association (OCA)", + "maintainers": ["mmequignon"], + "license": "AGPL-3", + "installable": True, + "auto_install": False, + "external_dependencies": { + "python": ["odoo_test_helper"], + }, + "depends": [ + "mail", + ], + "data": [ + "views/ir_model.xml", + ], +} diff --git a/outgoing_email_by_model/i18n/outgoing_email_by_model.pot b/outgoing_email_by_model/i18n/outgoing_email_by_model.pot new file mode 100644 index 0000000000..8ff8cb3672 --- /dev/null +++ b/outgoing_email_by_model/i18n/outgoing_email_by_model.pot @@ -0,0 +1,50 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * outgoing_email_by_model +# +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: outgoing_email_by_model +#: model:ir.model.fields,help:outgoing_email_by_model.field_ir_model__outgoing_email +msgid "" +"\n" +" Allows to force the usage of a given email address if this setting is set.\n" +" However, this setting will be active only if the model extends `mail.thread`.\n" +msgstr "" + +#. module: outgoing_email_by_model +#: model:ir.model.fields,help:outgoing_email_by_model.field_ir_model__outgoing_mailserver_id +msgid "" +"\n" +" Allows to force the usage of a given outgoing mail server if this setting is set.\n" +" However, this setting will be active only if the model extends `mail.thread`.\n" +msgstr "" + +#. module: outgoing_email_by_model +#: model:ir.model,name:outgoing_email_by_model.model_mail_thread +msgid "Email Thread" +msgstr "" + +#. module: outgoing_email_by_model +#: model:ir.model,name:outgoing_email_by_model.model_ir_model +msgid "Models" +msgstr "" + +#. module: outgoing_email_by_model +#: model:ir.model.fields,field_description:outgoing_email_by_model.field_ir_model__outgoing_email +msgid "Outgoing Email" +msgstr "" + +#. module: outgoing_email_by_model +#: model:ir.model.fields,field_description:outgoing_email_by_model.field_ir_model__outgoing_mailserver_id +msgid "Outgoing Mailserver" +msgstr "" diff --git a/outgoing_email_by_model/models/__init__.py b/outgoing_email_by_model/models/__init__.py new file mode 100644 index 0000000000..2fd012eabc --- /dev/null +++ b/outgoing_email_by_model/models/__init__.py @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Groupe Voltaire +# @author Emilie SOUTIRAS +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import ir_model +from . import mail_thread diff --git a/outgoing_email_by_model/models/ir_model.py b/outgoing_email_by_model/models/ir_model.py new file mode 100644 index 0000000000..70e29a9891 --- /dev/null +++ b/outgoing_email_by_model/models/ir_model.py @@ -0,0 +1,23 @@ +# Copyright (c) 2024 Groupe Voltaire +# @author Emilie SOUTIRAS +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + +OUTGOING_MAILSERVER_DESCRIPTION = """ + Allows to force the usage of a given outgoing mail server if this setting is set. + However, this setting will be active only if the model extends `mail.thread`. +""" +OUTGOING_EMAIL_DESCRIPTION = """ + Allows to force the usage of a given email address if this setting is set. + However, this setting will be active only if the model extends `mail.thread`. +""" + + +class IrModel(models.Model): + _inherit = "ir.model" + + outgoing_mailserver_id = fields.Many2one( + "ir.mail_server", help=OUTGOING_MAILSERVER_DESCRIPTION + ) + outgoing_email = fields.Char(help=OUTGOING_EMAIL_DESCRIPTION) diff --git a/outgoing_email_by_model/models/mail_thread.py b/outgoing_email_by_model/models/mail_thread.py new file mode 100644 index 0000000000..52bfe50a1a --- /dev/null +++ b/outgoing_email_by_model/models/mail_thread.py @@ -0,0 +1,24 @@ +# Copyright (c) 2024 Groupe Voltaire +# @author Emilie SOUTIRAS +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models + + +class MailThread(models.AbstractModel): + _inherit = "mail.thread" + + def _notify_by_email_get_final_mail_values( + self, recipient_ids, base_mail_values, additional_values=None + ): + res = super()._notify_by_email_get_final_mail_values( + recipient_ids, base_mail_values, additional_values=additional_values + ) + model = self.env["ir.model"].sudo().search([("model", "=", self._name)]) + custom_mailserver = model.outgoing_mailserver_id + if custom_mailserver: + res.update({"mail_server_id": custom_mailserver.id}) + custom_email = model.outgoing_email + if custom_email: + res.update({"email_from": custom_email}) + return res diff --git a/outgoing_email_by_model/readme/CONFIGURE.rst b/outgoing_email_by_model/readme/CONFIGURE.rst new file mode 100644 index 0000000000..1626e169d1 --- /dev/null +++ b/outgoing_email_by_model/readme/CONFIGURE.rst @@ -0,0 +1,4 @@ +If you want to use a specific outgoing mail for a model, populate the following fields in the model record (Settings > Technical > Models) accordingly: + +* Outgoing Mailserver: Set an outgoing mail server. This will be used as the forced outgoing mail server for the model. +* Outgoing Email: Set an email address. This will be used as the outgoing email for the model. diff --git a/outgoing_email_by_model/readme/CONTRIBUTORS.rst b/outgoing_email_by_model/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..4b05d96c81 --- /dev/null +++ b/outgoing_email_by_model/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Emilie SOUTIRAS diff --git a/outgoing_email_by_model/readme/DESCRIPTION.rst b/outgoing_email_by_model/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..cd105d0ff5 --- /dev/null +++ b/outgoing_email_by_model/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +Allow to select an outgoing mail parameters per model, such as email_from, or mail_server_id. + +To make it work, the model must inherit `mail.thread`. diff --git a/outgoing_email_by_model/static/description/icon.png b/outgoing_email_by_model/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/outgoing_email_by_model/static/description/icon.png differ diff --git a/outgoing_email_by_model/static/description/index.html b/outgoing_email_by_model/static/description/index.html new file mode 100644 index 0000000000..67531c53e3 --- /dev/null +++ b/outgoing_email_by_model/static/description/index.html @@ -0,0 +1,435 @@ + + + + + +Outgoing Email by Model + + + +
+

Outgoing Email by Model

+ + +

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

+

Allow to select an outgoing mail parameters per model, such as email_from, or mail_server_id.

+

To make it work, the model must inherit mail.thread.

+

Table of contents

+ +
+

Configuration

+

If you want to use a specific outgoing mail for a model, populate the following fields in the model record (Settings > Technical > Models) accordingly:

+
    +
  • Outgoing Mailserver: Set an outgoing mail server. This will be used as the forced outgoing mail server for the model.
  • +
  • Outgoing Email: Set an email address. This will be used as the outgoing email for the model.
  • +
+
+
+

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

+
    +
  • Camptocamp
  • +
+
+ +
+

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:

+

mmequignon

+

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/outgoing_email_by_model/tests/__init__.py b/outgoing_email_by_model/tests/__init__.py new file mode 100644 index 0000000000..92c998b19b --- /dev/null +++ b/outgoing_email_by_model/tests/__init__.py @@ -0,0 +1 @@ +from . import test_mailserver_by_model diff --git a/outgoing_email_by_model/tests/models.py b/outgoing_email_by_model/tests/models.py new file mode 100644 index 0000000000..65066f92fe --- /dev/null +++ b/outgoing_email_by_model/tests/models.py @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Groupe Voltaire +# @author Emilie SOUTIRAS +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ModelWithMail(models.Model): + _name = "model.with.mail" + _inherit = ["mail.thread"] + + partner_id = fields.Many2one("res.partner") diff --git a/outgoing_email_by_model/tests/test_mailserver_by_model.py b/outgoing_email_by_model/tests/test_mailserver_by_model.py new file mode 100644 index 0000000000..dabef0e59a --- /dev/null +++ b/outgoing_email_by_model/tests/test_mailserver_by_model.py @@ -0,0 +1,99 @@ +# Copyright (c) 2024 Groupe Voltaire +# @author Emilie SOUTIRAS +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo_test_helper import FakeModelLoader + +from odoo.tests.common import Form, TransactionCase + + +class TestMailserverByModel(TransactionCase): + at_install = False + post_install = True + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.setUpClassModels() + cls.setUpClassMailserver() + cls.setUpClassMail() + + @classmethod + def tearDownClass(cls): + cls.loader.restore_registry() + return super().tearDownClass() + + @classmethod + def setUpClassModels(cls): + cls.loader = FakeModelLoader(cls.env, cls.__module__) + cls.loader.backup_registry() + from .models import ModelWithMail + + cls.loader.update_registry((ModelWithMail,)) + dest_partner = cls.env["res.partner"].create( + {"name": "René Coty", "email": "rene.coty@gouv.fr"} + ) + cls.record_with_mail = cls.env[ModelWithMail._name].create( + {"partner_id": dest_partner.id} + ) + cls.model_with_mail_model = cls.env["ir.model"].search( + [("model", "=", ModelWithMail._name)] + ) + + @classmethod + def setUpClassMailserver(cls): + mailserver_model = cls.env["ir.mail_server"] + cls.secondary_mailserver = mailserver_model.create( + { + "smtp_host": "localhost", + "smtp_port": "25", + "smtp_pass": "1 4m v3ry 53cur3", + "smtp_authentication": "login", + "smtp_encryption": "none", + "name": "secondary", + "smtp_user": "secondary@localhost", + "sequence": 42, + } + ) + + @classmethod + def setUpClassMail(cls): + cls.mail_template = cls.env["mail.template"].create( + { + "model_id": cls.model_with_mail_model.id, + "name": "Model with Mail: Send by Mail", + "subject": "Model with Mail: {{object.partner_id.name}}", + "partner_to": "{{object.partner_id.id}}", + "body_html": "Hello, this is a mail", + } + ) + + def _write_message_on_record(self, record): + composer = Form( + self.env["mail.compose.message"].with_context( + default_model=record._name, + default_res_id=record.id, + default_use_template=True, + default_template_id=self.mail_template.id, + default_composition_mode="comment", + ) + ) + composer.save().action_send_mail() + return record.message_ids[0] + + def test_mail_server(self): + # By default, message.mail_server_id is False + message = self._write_message_on_record(self.record_with_mail) + self.assertFalse(message.mail_server_id) + # But if we set outgoing_mailserver_id on the model, secondary_mailserver + # is forced. + self.model_with_mail_model.write( + { + "outgoing_mailserver_id": self.secondary_mailserver.id, + "outgoing_email": self.secondary_mailserver.smtp_user, + } + ) + message = self._write_message_on_record(self.record_with_mail) + self.assertEqual(message.mail_server_id, self.secondary_mailserver) + self.assertEqual(message.email_from, self.secondary_mailserver.smtp_user) diff --git a/outgoing_email_by_model/views/ir_model.xml b/outgoing_email_by_model/views/ir_model.xml new file mode 100644 index 0000000000..0bd73a5b46 --- /dev/null +++ b/outgoing_email_by_model/views/ir_model.xml @@ -0,0 +1,29 @@ + + + + + + ir.model.form.inherit + ir.model + + + + + + + + + + diff --git a/setup/outgoing_email_by_model/odoo/addons/outgoing_email_by_model b/setup/outgoing_email_by_model/odoo/addons/outgoing_email_by_model new file mode 120000 index 0000000000..44f6a2eb4f --- /dev/null +++ b/setup/outgoing_email_by_model/odoo/addons/outgoing_email_by_model @@ -0,0 +1 @@ +../../../../outgoing_email_by_model \ No newline at end of file diff --git a/setup/outgoing_email_by_model/setup.py b/setup/outgoing_email_by_model/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/outgoing_email_by_model/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)