diff --git a/partner_mobile_duplicate_warn/README.rst b/partner_mobile_duplicate_warn/README.rst new file mode 100644 index 000000000..d8c920736 --- /dev/null +++ b/partner_mobile_duplicate_warn/README.rst @@ -0,0 +1 @@ +Will be generated from the README subdir diff --git a/partner_mobile_duplicate_warn/__init__.py b/partner_mobile_duplicate_warn/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/partner_mobile_duplicate_warn/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/partner_mobile_duplicate_warn/__manifest__.py b/partner_mobile_duplicate_warn/__manifest__.py new file mode 100644 index 000000000..ff0233767 --- /dev/null +++ b/partner_mobile_duplicate_warn/__manifest__.py @@ -0,0 +1,23 @@ +# 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 Mobile 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 mobile", + "author": "Akretion,Odoo Community Association (OCA)", + "maintainers": ["alexis-via"], + "website": "https://github.com/OCA/partner-contact", + "depends": ["phone_validation"], + # I add phonenumbers in external_dependencies + # because the phone_validation module doesn't do it + # and it's needed for Travis + "external_dependencies": {"python": ["phonenumbers"]}, + "data": [ + "views/res_partner.xml", + ], + "installable": True, +} diff --git a/partner_mobile_duplicate_warn/models/__init__.py b/partner_mobile_duplicate_warn/models/__init__.py new file mode 100644 index 000000000..91fed54d4 --- /dev/null +++ b/partner_mobile_duplicate_warn/models/__init__.py @@ -0,0 +1 @@ +from . import res_partner diff --git a/partner_mobile_duplicate_warn/models/res_partner.py b/partner_mobile_duplicate_warn/models/res_partner.py new file mode 100644 index 000000000..687242961 --- /dev/null +++ b/partner_mobile_duplicate_warn/models/res_partner.py @@ -0,0 +1,40 @@ +# 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_mobile_partner_id = fields.Many2one( + "res.partner", + compute="_compute_same_mobile_partner_id", + string="Partner with same mobile", + compute_sudo=True, + ) + + @api.depends("mobile", "company_id") + def _compute_same_mobile_partner_id(self): + # With phone_validation, the "mobile" field should be + # clean in E.164 format, without any start/ending spaces + # So we search on the 'mobile' field with '=' ! + for partner in self: + same_mobile_partner_id = False + if partner.mobile: + domain = [("mobile", "=", partner.mobile)] + if partner.company_id: + domain += [ + "|", + ("company_id", "=", False), + ("company_id", "=", partner.company_id.id), + ] + partner_id = partner._origin.id + if partner_id: + domain.append(("id", "!=", partner_id)) + same_mobile_partner = self.with_context(active_test=False).search( + domain, limit=1 + ) + same_mobile_partner_id = same_mobile_partner.id or False + partner.same_mobile_partner_id = same_mobile_partner_id diff --git a/partner_mobile_duplicate_warn/readme/CONFIGURE.rst b/partner_mobile_duplicate_warn/readme/CONFIGURE.rst new file mode 100644 index 000000000..e7dc23597 --- /dev/null +++ b/partner_mobile_duplicate_warn/readme/CONFIGURE.rst @@ -0,0 +1 @@ +No configuration required. diff --git a/partner_mobile_duplicate_warn/readme/CONTRIBUTORS.rst b/partner_mobile_duplicate_warn/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..ff65d68ce --- /dev/null +++ b/partner_mobile_duplicate_warn/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Alexis de Lattre diff --git a/partner_mobile_duplicate_warn/readme/DESCRIPTION.rst b/partner_mobile_duplicate_warn/readme/DESCRIPTION.rst new file mode 100644 index 000000000..4597dea57 --- /dev/null +++ b/partner_mobile_duplicate_warn/readme/DESCRIPTION.rst @@ -0,0 +1,8 @@ +This module adds a warning banner on the partner form view if another partner has the same mobile phone number. 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 + +This module depend on the module *phone_validation* from the official addons which handle the automatic reformatting of phone numbers to the E.164 format depending on the country of the partner. For exemple, for a French partner, if you write **06.23.45.67.78** in the *Mobile* field, it will be automatically reformatted to **+33 6 23 45 67 78** (via the onchange). Thanks to this reformatting, this module can easily find identical phone numbers on other partners. + +It is similar to the native warning banner when another partner has the same VAT number. This module has a twin brother named **partner_email_duplicate_warn** which adds a warning banner when another partner has the same email. diff --git a/partner_mobile_duplicate_warn/readme/USAGE.rst b/partner_mobile_duplicate_warn/readme/USAGE.rst new file mode 100644 index 000000000..78e6af38a --- /dev/null +++ b/partner_mobile_duplicate_warn/readme/USAGE.rst @@ -0,0 +1,4 @@ +The warning banner is displayed on the partner form view if another partner: +- has the same mobile phone number (the module *phone_validation* ensure that phone numbers are automatically formatted to the E.164 format), +- 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_mobile_duplicate_warn/static/description/partner_warn_banner.png b/partner_mobile_duplicate_warn/static/description/partner_warn_banner.png new file mode 100644 index 000000000..0bc5628d5 Binary files /dev/null and b/partner_mobile_duplicate_warn/static/description/partner_warn_banner.png differ diff --git a/partner_mobile_duplicate_warn/tests/__init__.py b/partner_mobile_duplicate_warn/tests/__init__.py new file mode 100644 index 000000000..d8d7ecafe --- /dev/null +++ b/partner_mobile_duplicate_warn/tests/__init__.py @@ -0,0 +1 @@ +from . import test_mobile_duplicate diff --git a/partner_mobile_duplicate_warn/tests/test_mobile_duplicate.py b/partner_mobile_duplicate_warn/tests/test_mobile_duplicate.py new file mode 100644 index 000000000..1ec34a8a4 --- /dev/null +++ b/partner_mobile_duplicate_warn/tests/test_mobile_duplicate.py @@ -0,0 +1,74 @@ +# 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.fr_country_id = self.env.ref("base.fr").id + self.partner_simple = self.env["res.partner"].create( + { + "name": "Alexia Payet", + "mobile": " +33699887766 ", + "country_id": self.fr_country_id, + } + ) + self.partner_simple._onchange_mobile_validation() + 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", + "mobile": "06 99 88 77 65", + "country_id": self.fr_country_id, + } + ) + partner1._onchange_mobile_validation() + self.assertFalse(partner1.same_mobile_partner_id) + partner1.write({"mobile": " 06 99 88 77 66"}) + partner1._onchange_mobile_validation() + self.assertEqual(partner1.same_mobile_partner_id, self.partner_simple) + + def test_partner_duplicate_multi_company(self): + partner_company1 = self.env["res.partner"].create( + { + "name": "Toto", + "mobile": "+33 6 11 22 33 44", + "company_id": self.company1_id, + } + ) + partner_company2 = self.env["res.partner"].create( + { + "name": "Toto", + "mobile": "+33 6 11 22 33 44", + "company_id": self.company2_id, + } + ) + self.assertFalse(partner_company1.same_mobile_partner_id) + self.assertFalse(partner_company2.same_mobile_partner_id) + partner_company2.write({"company_id": False}) + self.assertEqual(partner_company2.same_mobile_partner_id, partner_company1) diff --git a/partner_mobile_duplicate_warn/views/res_partner.xml b/partner_mobile_duplicate_warn/views/res_partner.xml new file mode 100644 index 000000000..85b6370b4 --- /dev/null +++ b/partner_mobile_duplicate_warn/views/res_partner.xml @@ -0,0 +1,25 @@ + + + + + res.partner + + +
+ +
+
+
+ +
diff --git a/requirements.txt b/requirements.txt index bcfab71c0..41b756f38 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ # generated from manifests external_dependencies email-validator +phonenumbers diff --git a/setup/partner_mobile_duplicate_warn/odoo/addons/partner_mobile_duplicate_warn b/setup/partner_mobile_duplicate_warn/odoo/addons/partner_mobile_duplicate_warn new file mode 120000 index 000000000..1b8a0dbe5 --- /dev/null +++ b/setup/partner_mobile_duplicate_warn/odoo/addons/partner_mobile_duplicate_warn @@ -0,0 +1 @@ +../../../../partner_mobile_duplicate_warn \ No newline at end of file diff --git a/setup/partner_mobile_duplicate_warn/setup.py b/setup/partner_mobile_duplicate_warn/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/partner_mobile_duplicate_warn/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)