diff --git a/partner_email_duplicate_warn/README.rst b/partner_email_duplicate_warn/README.rst new file mode 100644 index 000000000..d8c920736 --- /dev/null +++ b/partner_email_duplicate_warn/README.rst @@ -0,0 +1 @@ +Will be generated from the README subdir diff --git a/partner_email_duplicate_warn/__init__.py b/partner_email_duplicate_warn/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/partner_email_duplicate_warn/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/partner_email_duplicate_warn/__manifest__.py b/partner_email_duplicate_warn/__manifest__.py new file mode 100644 index 000000000..d8f8fc6e9 --- /dev/null +++ b/partner_email_duplicate_warn/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Partner Email Duplicate Warn", + "version": "14.0.1.0.0", + "category": "Partner Management", + "license": "AGPL-3", + "summary": "Warning banner on partner form if another partner has the same email", + "author": "Akretion,Odoo Community Association (OCA)", + "maintainers": ["alexis-via"], + "website": "https://github.com/OCA/partner-contact", + "depends": ["base"], + "data": [ + "views/res_partner.xml", + ], + "installable": True, +} diff --git a/partner_email_duplicate_warn/models/__init__.py b/partner_email_duplicate_warn/models/__init__.py new file mode 100644 index 000000000..91fed54d4 --- /dev/null +++ b/partner_email_duplicate_warn/models/__init__.py @@ -0,0 +1 @@ +from . import res_partner diff --git a/partner_email_duplicate_warn/models/res_partner.py b/partner_email_duplicate_warn/models/res_partner.py new file mode 100644 index 000000000..cf83a48ea --- /dev/null +++ b/partner_email_duplicate_warn/models/res_partner.py @@ -0,0 +1,48 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + same_email_partner_id = fields.Many2one( + "res.partner", + compute="_compute_same_email_partner_id", + string="Partner with same e-mail", + compute_sudo=True, + ) + + @api.depends("email", "company_id") + def _compute_same_email_partner_id(self): + for partner in self: + same_email_partner_id = False + if partner.email and partner.email.strip(): + partner_email = partner.email.strip().lower() + domain = [("email", "=ilike", "%" + partner_email + "%")] + if partner.company_id: + domain += [ + "|", + ("company_id", "=", False), + ("company_id", "=", partner.company_id.id), + ] + partner_id = partner._origin.id + if partner_id: + domain += [ + ("id", "!=", partner_id), + "!", + ("id", "child_of", partner_id), + "!", + ("id", "parent_of", partner_id), + ] + search_partners = self.with_context(active_test=False).search(domain) + for search_partner in search_partners: + if ( + search_partner.email + and search_partner.email.strip().lower() == partner_email + ): + same_email_partner_id = search_partner + break + partner.same_email_partner_id = same_email_partner_id diff --git a/partner_email_duplicate_warn/readme/CONFIGURE.rst b/partner_email_duplicate_warn/readme/CONFIGURE.rst new file mode 100644 index 000000000..e7dc23597 --- /dev/null +++ b/partner_email_duplicate_warn/readme/CONFIGURE.rst @@ -0,0 +1 @@ +No configuration required. diff --git a/partner_email_duplicate_warn/readme/CONTRIBUTORS.rst b/partner_email_duplicate_warn/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..ff65d68ce --- /dev/null +++ b/partner_email_duplicate_warn/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Alexis de Lattre diff --git a/partner_email_duplicate_warn/readme/DESCRIPTION.rst b/partner_email_duplicate_warn/readme/DESCRIPTION.rst new file mode 100644 index 000000000..6d6d92c4d --- /dev/null +++ b/partner_email_duplicate_warn/readme/DESCRIPTION.rst @@ -0,0 +1,7 @@ +This module adds a warning banner on the partner form view if another partner has the same e-mail. It helps spot duplicate partners. If the duplication is confirmed, the user can then use the native partner merge wizard available from the partner tree view (menu *Action > Merge*). + +.. figure:: static/description/partner_warn_banner.png + :alt: Warning banner on partner form + +It is similar to the native warning banner when another partner has the same VAT number. T +his module has a twin brother named **partner_mobile_duplicate_warn** which adds a warning banner when another partner has the same mobile phone number. diff --git a/partner_email_duplicate_warn/readme/USAGE.rst b/partner_email_duplicate_warn/readme/USAGE.rst new file mode 100644 index 000000000..0e67ae8fa --- /dev/null +++ b/partner_email_duplicate_warn/readme/USAGE.rst @@ -0,0 +1,5 @@ +The warning banner is displayed on the partner form view if another partner: +- has the same e-mail address (independantly from the case, from starting spaces and ending spaces), +- is not the parent nor the child of the partner, +- if the partner is attached to a specific company: is in the same company or is not attached to a specific company, +- if the partner is not attached to a specific company: is in any company or not attached to a specific company. diff --git a/partner_email_duplicate_warn/static/description/partner_warn_banner.png b/partner_email_duplicate_warn/static/description/partner_warn_banner.png new file mode 100644 index 000000000..1db912e05 Binary files /dev/null and b/partner_email_duplicate_warn/static/description/partner_warn_banner.png differ diff --git a/partner_email_duplicate_warn/tests/__init__.py b/partner_email_duplicate_warn/tests/__init__.py new file mode 100644 index 000000000..298716c2e --- /dev/null +++ b/partner_email_duplicate_warn/tests/__init__.py @@ -0,0 +1 @@ +from . import test_email_duplicate diff --git a/partner_email_duplicate_warn/tests/test_email_duplicate.py b/partner_email_duplicate_warn/tests/test_email_duplicate.py new file mode 100644 index 000000000..1a84a31bc --- /dev/null +++ b/partner_email_duplicate_warn/tests/test_email_duplicate.py @@ -0,0 +1,127 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.tests import tagged +from odoo.tests.common import TransactionCase + + +@tagged("post_install", "-at_install") +class TestResPartner(TransactionCase): + def setUp(self): + super().setUp() + self.partner_simple = self.env["res.partner"].create( + { + "name": "Alexia Payet", + "email": "alexia.payet@akretion.com", + } + ) + self.partner_space_start = self.env["res.partner"].create( + { + "name": "Alexia Payet", + "email": " alexia.payet@videolan.org", + } + ) + self.partner_space_end = self.env["res.partner"].create( + { + "name": "Alexia Payet", + "email": "alexia.payet@via.ecp.fr ", + } + ) + self.company1_id = self.env.ref("base.main_company").id + partner_company = self.env["res.partner"].create( + { + "name": "Test Company", + "is_company": True, + "country_id": self.env.ref("base.fr").id, + } + ) + self.company2_id = ( + self.env["res.company"] + .create( + { + "name": "Test Company", + "partner_id": partner_company.id, + "currency_id": self.env.ref("base.EUR").id, + } + ) + .id + ) + + def test_partner_duplicate_simple(self): + partner1 = self.env["res.partner"].create( + { + "name": "Test regular", + "email": "alexis.payet@akretion.com", + } + ) + self.assertFalse(partner1.same_email_partner_id) + partner1.write({"email": "alexia.payet@akretion.com"}) + self.assertEqual(partner1.same_email_partner_id, self.partner_simple) + + def test_partner_duplicate_spaces_caps(self): + partner2 = self.env["res.partner"].create( + { + "name": "Test space", + "email": "alexia.payet@videolan.org", + } + ) + self.assertEqual(partner2.same_email_partner_id, self.partner_space_start) + partner2.write({"email": "alexia.payet@videolan.org "}) + self.assertEqual(partner2.same_email_partner_id, self.partner_space_start) + partner2.write({"email": " alexia.payet@videolan.org"}) + self.assertEqual(partner2.same_email_partner_id, self.partner_space_start) + partner2.write({"email": " Alexia.Payet@videolan.org "}) + self.assertEqual(partner2.same_email_partner_id, self.partner_space_start) + partner2.write({"email": "Alexia.Pazet@videolan.org"}) + self.assertFalse(partner2.same_email_partner_id) + partner3 = self.env["res.partner"].create( + { + "name": "Test space2", + "email": "Alexia.Payet@via.ecp.fr", + } + ) + self.assertEqual(partner3.same_email_partner_id, self.partner_space_end) + partner3.write({"email": " Alexia.Payet@via.ecp.fr"}) + self.assertEqual(partner3.same_email_partner_id, self.partner_space_end) + partner3.write({"email": " Alexia.Payet@Via.Ecp.Fr "}) + self.assertEqual(partner3.same_email_partner_id, self.partner_space_end) + + def test_partner_duplicate_multi_company(self): + partner_company1 = self.env["res.partner"].create( + { + "name": "Toto", + "email": "alexandra.payet@via.ecp.fr", + "company_id": self.company1_id, + } + ) + partner_company2 = self.env["res.partner"].create( + { + "name": "Toto", + "email": "alexandra.payet@via.ecp.fr", + "company_id": self.company2_id, + } + ) + self.assertFalse(partner_company1.same_email_partner_id) + self.assertFalse(partner_company2.same_email_partner_id) + partner_company2.write({"company_id": False}) + self.assertEqual(partner_company2.same_email_partner_id, partner_company1) + + def test_partner_duplicate_parent_child(self): + parent_partner = self.env["res.partner"].create( + { + "name": "Rocket Corp", + "is_company": True, + "email": "contact@rocket.com", + } + ) + child_partner = self.env["res.partner"].create( + { + "name": "M. Dupont", + "is_company": False, + "parent_id": parent_partner.id, + "email": "contact@rocket.com", + } + ) + self.assertFalse(parent_partner.same_email_partner_id) + self.assertFalse(child_partner.same_email_partner_id) diff --git a/partner_email_duplicate_warn/views/res_partner.xml b/partner_email_duplicate_warn/views/res_partner.xml new file mode 100644 index 000000000..12114eed7 --- /dev/null +++ b/partner_email_duplicate_warn/views/res_partner.xml @@ -0,0 +1,25 @@ + + + + + res.partner + + +
+ +
+
+
+ +
diff --git a/setup/partner_email_duplicate_warn/odoo/addons/partner_email_duplicate_warn b/setup/partner_email_duplicate_warn/odoo/addons/partner_email_duplicate_warn new file mode 120000 index 000000000..cc33e02b6 --- /dev/null +++ b/setup/partner_email_duplicate_warn/odoo/addons/partner_email_duplicate_warn @@ -0,0 +1 @@ +../../../../partner_email_duplicate_warn \ No newline at end of file diff --git a/setup/partner_email_duplicate_warn/setup.py b/setup/partner_email_duplicate_warn/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/partner_email_duplicate_warn/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)