From 96a004710c579759ad1aa27d1360c77b71f2be1e Mon Sep 17 00:00:00 2001
From: Fabien Pinckaers <fp@openerp.com>
Date: Thu, 13 Apr 2017 13:33:58 +0200
Subject: [PATCH] [ADD] phone_validation: tool module allowing phone number
 validation

Using phonenumbers library this module adds tools methods as well as a
small mixin for models that want to activate phone number validation
and formatting.

Formatting can be done always using an international format or having
both national and international format. This is configured on the
company.

Note that phonenumbers library is optional. Installing this module without
having the lib installed just skip its use but should not crash.
---
 addons/phone_validation/__init__.py           |  5 ++
 addons/phone_validation/__manifest__.py       | 21 +++++++
 addons/phone_validation/models/__init__.py    |  5 ++
 .../models/phone_validation_mixin.py          | 29 +++++++++
 addons/phone_validation/models/res_company.py | 15 +++++
 addons/phone_validation/tools/__init__.py     |  4 ++
 .../tools/phone_validation.py                 | 59 +++++++++++++++++++
 7 files changed, 138 insertions(+)
 create mode 100644 addons/phone_validation/__init__.py
 create mode 100644 addons/phone_validation/__manifest__.py
 create mode 100644 addons/phone_validation/models/__init__.py
 create mode 100644 addons/phone_validation/models/phone_validation_mixin.py
 create mode 100644 addons/phone_validation/models/res_company.py
 create mode 100644 addons/phone_validation/tools/__init__.py
 create mode 100644 addons/phone_validation/tools/phone_validation.py

diff --git a/addons/phone_validation/__init__.py b/addons/phone_validation/__init__.py
new file mode 100644
index 000000000000..3d097a1fcdf3
--- /dev/null
+++ b/addons/phone_validation/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import tools
+from . import models
diff --git a/addons/phone_validation/__manifest__.py b/addons/phone_validation/__manifest__.py
new file mode 100644
index 000000000000..dc21476150f8
--- /dev/null
+++ b/addons/phone_validation/__manifest__.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+{
+    'name': 'Phone Numbers Validation',
+    'summary': 'Validate and format phone numbers',
+    'sequence': '9999',
+    'category': 'Hidden',
+    'description': """
+Phone Numbers Validation
+========================
+
+This module adds the feature of validation and formatting phone numbers
+according to a destination country. It also handles national and international
+formatting.
+
+This module applies this feature to Leads and Contacts.""",
+    'data': [
+    ],
+    'depends': ['base'],
+}
diff --git a/addons/phone_validation/models/__init__.py b/addons/phone_validation/models/__init__.py
new file mode 100644
index 000000000000..85ea05974835
--- /dev/null
+++ b/addons/phone_validation/models/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import res_company
+from . import phone_validation_mixin
diff --git a/addons/phone_validation/models/phone_validation_mixin.py b/addons/phone_validation/models/phone_validation_mixin.py
new file mode 100644
index 000000000000..8391e89cea31
--- /dev/null
+++ b/addons/phone_validation/models/phone_validation_mixin.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models
+from odoo.addons.phone_validation.tools import phone_validation
+
+
+class PhoneValidationMixin(models.AbstractModel):
+    _name = 'phone.validation.mixin'
+
+    def _phone_get_country_code(self):
+        if 'country_id' in self:
+            return self.country_id.code
+        return self.env.user.company_id.country_id.code
+
+    def _phone_get_always_international(self):
+        if 'company_id' in self:
+            return self.company_id.phone_international_format
+        return self.env.user.company_id.phone_international_format
+
+    def phone_format(self, number, country=None, company=None):
+        country_code = country.code if country else self._phone_get_country_code()
+        always_international = company.phone_international_format if company else self._phone_get_always_international()
+
+        return phone_validation.phone_format(
+            number, country_code if country_code else None,
+            always_international=always_international,
+            raise_exception=True
+        )
diff --git a/addons/phone_validation/models/res_company.py b/addons/phone_validation/models/res_company.py
new file mode 100644
index 000000000000..40dab76d7a79
--- /dev/null
+++ b/addons/phone_validation/models/res_company.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import fields, models
+
+
+class ResCompany(models.Model):
+    _inherit = 'res.company'
+
+    phone_international_format = fields.Boolean(
+        string="Enforce International Format", default=False,
+        help="Always encore phone numbers using international format. Otherwise"
+             "numbers coming from the company's country are nationaly formatted."
+             "International numbers are always using international format."
+    )
diff --git a/addons/phone_validation/tools/__init__.py b/addons/phone_validation/tools/__init__.py
new file mode 100644
index 000000000000..1c27cd6ebed3
--- /dev/null
+++ b/addons/phone_validation/tools/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import phone_validation
diff --git a/addons/phone_validation/tools/phone_validation.py b/addons/phone_validation/tools/phone_validation.py
new file mode 100644
index 000000000000..92b12cea1e06
--- /dev/null
+++ b/addons/phone_validation/tools/phone_validation.py
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import _
+from odoo.exceptions import UserError
+
+import logging
+
+_logger = logging.getLogger(__name__)
+_phonenumbers_lib_warning = False
+
+
+try:
+    import phonenumbers
+
+    def phone_parse(number, country_code):
+        try:
+            phone_nbr = phonenumbers.parse(number, region=country_code, keep_raw_input=True)
+        except phonenumbers.phonenumberutil.NumberParseException as e:
+            raise UserError(_('Unable to parse %s:\n%s') % (number, e))
+
+        if not phonenumbers.is_possible_number(phone_nbr):
+            raise UserError(_('Impossible number %s: probably invalid number of digits') % number)
+        if not phonenumbers.is_valid_number(phone_nbr):
+            raise UserError(_('Invalid number %s: probably incorrect prefix') % number)
+
+        return phone_nbr
+
+    def phone_format(number, country_code, always_international=True, raise_exception=True):
+        try:
+            phone_nbr = phone_parse(number, country_code)
+        except (phonenumbers.phonenumberutil.NumberParseException, UserError) as e:
+            if raise_exception:
+                raise
+            else:
+                _logger.warning(_('Unable to format %s:\n%s') % number, e)
+                return number
+
+        if always_international and phone_nbr.country_code != country_code:
+            phone_fmt = phonenumbers.PhoneNumberFormat.INTERNATIONAL
+        else:
+            phone_fmt = phonenumbers.PhoneNumberFormat.NATIONAL
+
+        return phonenumbers.format_number(phone_nbr, phone_fmt)
+
+except ImportError:
+
+    def phone_parse(number, country_code):
+        return False
+
+    def phone_format(number, country_code, always_international=True, raise_exception=True):
+        global _phonenumbers_lib_warning
+        if not _phonenumbers_lib_warning:
+            _logger.warning(
+                "The `phonenumbers` Python module is not installed, contact numbers will not be "
+                "verified. Try: pip install phonenumbers."
+            )
+            _phonenumbers_lib_warning = True
+        return number
-- 
GitLab