summaryrefslogtreecommitdiff
path: root/addons/phone_validation/tools
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/phone_validation/tools
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/phone_validation/tools')
-rw-r--r--addons/phone_validation/tools/__init__.py4
-rw-r--r--addons/phone_validation/tools/phone_validation.py116
2 files changed, 120 insertions, 0 deletions
diff --git a/addons/phone_validation/tools/__init__.py b/addons/phone_validation/tools/__init__.py
new file mode 100644
index 00000000..1c27cd6e
--- /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 00000000..813f0e4f
--- /dev/null
+++ b/addons/phone_validation/tools/phone_validation.py
@@ -0,0 +1,116 @@
+# -*- 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 %(phone)s: %(error)s', phone=number, error=str(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, country_phone_code, force_format='INTERNATIONAL', raise_exception=True):
+ """ Format the given phone number according to the localisation and international options.
+ :param number: number to convert
+ :param country_code: the ISO country code in two chars
+ :type country_code: str
+ :param country_phone_code: country dial in codes, defined by the ITU-T (Ex: 32 for Belgium)
+ :type country_phone_code: int
+ :param force_format: stringified version of format globals (see
+ https://github.com/daviddrysdale/python-phonenumbers/blob/dev/python/phonenumbers/phonenumberutil.py)
+ 'E164' = 0
+ 'INTERNATIONAL' = 1
+ 'NATIONAL' = 2
+ 'RFC3966' = 3
+ :type force_format: str
+ :rtype: str
+ """
+ try:
+ phone_nbr = phone_parse(number, country_code)
+ except (phonenumbers.phonenumberutil.NumberParseException, UserError) as e:
+ if raise_exception:
+ raise
+ else:
+ return number
+ if force_format == 'E164':
+ phone_fmt = phonenumbers.PhoneNumberFormat.E164
+ elif force_format == 'RFC3966':
+ phone_fmt = phonenumbers.PhoneNumberFormat.RFC3966
+ elif force_format == 'INTERNATIONAL' or phone_nbr.country_code != country_phone_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, country_phone_code, force_format='INTERNATIONAL', raise_exception=True):
+ global _phonenumbers_lib_warning
+ if not _phonenumbers_lib_warning:
+ _logger.info(
+ "The `phonenumbers` Python module is not installed, contact numbers will not be "
+ "verified. Please install the `phonenumbers` Python module."
+ )
+ _phonenumbers_lib_warning = True
+ return number
+
+
+def phone_sanitize_numbers(numbers, country_code, country_phone_code, force_format='E164'):
+ """ Given a list of numbers, return parsezd and sanitized information
+
+ :return dict: {number: {
+ 'sanitized': sanitized and formated number or False (if cannot format)
+ 'code': 'empty' (number was a void string), 'invalid' (error) or False (sanitize ok)
+ 'msg': error message when 'invalid'
+ }}
+ """
+ if not isinstance(numbers, (list)):
+ raise NotImplementedError()
+ result = dict.fromkeys(numbers, False)
+ for number in numbers:
+ if not number:
+ result[number] = {'sanitized': False, 'code': 'empty', 'msg': False}
+ continue
+ try:
+ stripped = number.strip()
+ sanitized = phone_format(
+ stripped, country_code, country_phone_code,
+ force_format=force_format, raise_exception=True)
+ except Exception as e:
+ result[number] = {'sanitized': False, 'code': 'invalid', 'msg': str(e)}
+ else:
+ result[number] = {'sanitized': sanitized, 'code': False, 'msg': False}
+ return result
+
+
+def phone_sanitize_numbers_w_record(numbers, record, country=False, record_country_fname='country_id', force_format='E164'):
+ if not isinstance(numbers, (list)):
+ raise NotImplementedError()
+ if not country:
+ if record and record_country_fname and hasattr(record, record_country_fname) and record[record_country_fname]:
+ country = record[record_country_fname]
+ elif record:
+ country = record.env.company.country_id
+ country_code = country.code if country else None
+ country_phone_code = country.phone_code if country else None
+ return phone_sanitize_numbers(numbers, country_code, country_phone_code, force_format=force_format)