summaryrefslogtreecommitdiff
path: root/addons/phone_validation/tools
diff options
context:
space:
mode:
authorThibault Delavallée <tde@odoo.com>2019-05-21 12:41:25 +0000
committerThibault Delavallée <tde@odoo.com>2019-07-02 10:40:46 +0000
commitdb177636540e632010bf5eebcd314b4c2f6960d3 (patch)
tree42c3b0353a93c1ecb152c1ab4b4e1101ab91141f /addons/phone_validation/tools
parent566244b47ba32f7d509fcb2ef15dcbed51009a0e (diff)
[IMP] phone_validation, sms: improve phone validation and SMS sending API
Purpose of this commit is to support more formatting options in phone tools, to provide new API methods for phone numbers validatio. It also introduces a method on sms.api to send SMS in batch. This one uses a new route given in IAP services that send a batch of SMS instead of sending them one by one. Concerning phone validation, tools are updated to correctly handle all format supported by phonenumbers library. Indeed in addition to national and international formatting phonenumbers library also supports E164 (international without spaces) and RFC3966 (beautification of phone numbers). Let us support them and ease the use of our small tool methods in various addons, notably sms. Cleaning / check tools methods are added in phone validation module. Various methods allow to sanitize phone numbers according to a context record and/or some parameters. Those tools will be used in upcoming sms refactoring. Another purpose of this commit is to add phone_validation in dependencies of SMS application. Phone_validation module adds tools to parse and format phone numbers and allow to replace the manual check done currently. Adding it in dependencies of SMS does not change anything functionally as * library is still optional. If phonenumbers library is not installed the features are skipped without crashing; * no model is modified as it introduces only tools and a mixin. Models are updated in crm_phone_validation that updates lead and partner models; Related to task 1922163 Linked to PR #34516 Co-Authored-By: Thibault Delavallee <tde@odoo.com> Co-Authored-By: Pierre Rousseau <pro@odoo.com>
Diffstat (limited to 'addons/phone_validation/tools')
-rw-r--r--addons/phone_validation/tools/phone_validation.py82
1 files changed, 73 insertions, 9 deletions
diff --git a/addons/phone_validation/tools/phone_validation.py b/addons/phone_validation/tools/phone_validation.py
index 7ca7bed6ea8..29828ffd739 100644
--- a/addons/phone_validation/tools/phone_validation.py
+++ b/addons/phone_validation/tools/phone_validation.py
@@ -26,14 +26,21 @@ try:
return phone_nbr
- def phone_format(number, country_code, country_phone_code, always_international=True, raise_exception=True):
+ 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
- :rtype: str
+ :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)
@@ -43,7 +50,11 @@ try:
else:
_logger.warning(_('Unable to format %s:\n%s'), number, e)
return number
- if always_international or phone_nbr.country_code != country_phone_code:
+ 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
@@ -54,7 +65,7 @@ except ImportError:
def phone_parse(number, country_code):
return False
- def phone_format(number, country_code, country_phone_code, always_international=True, raise_exception=True):
+ 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.warning(
@@ -63,3 +74,56 @@ except ImportError:
)
_phonenumbers_lib_warning = True
return number
+
+
+def phone_sanitize_numbers(numbers, country_code, country_phone_code, force_format='E164'):
+ valid, invalid, void_count = [], [], 0
+ for number in numbers:
+ if not number:
+ void_count += 1
+ continue
+ try:
+ sanitized = phone_format(
+ number, country_code, country_phone_code,
+ force_format=force_format, raise_exception=True)
+ except Exception as e:
+ invalid.append(number)
+ else:
+ valid.append(sanitized)
+ return valid, invalid, void_count
+
+
+def phone_sanitize_numbers_w_record(numbers, country_code, country_phone_code, record, record_country_fname='country_id', force_format='E164'):
+ if not country_code or not country_phone_code:
+ country = False
+ if record and record_country_fname in record and record[record_country_fname]:
+ country = record[record_country_fname]
+ elif record:
+ country = record.env.company.country_id
+ if country:
+ country_code = country_code if country_code else country.code
+ country_phone_code = country_phone_code if country_phone_code else country.phone_code
+ return phone_sanitize_numbers(numbers, country_code, country_phone_code, force_format=force_format)
+
+
+def phone_sanitize_numbers_string_w_record(numbers_str, country_code, country_phone_code, record, record_country_fname='country_id', force_format='E164'):
+ found_numbers = [number.strip() for number in numbers_str.split(',')]
+ return phone_sanitize_numbers_w_record(found_numbers, country_code, country_phone_code, record, record_country_fname, force_format=force_format)
+
+
+def phone_get_sanitized_records_number(records, number_fname='mobile', country_fname='country_id', force_format='E164'):
+ res = dict.fromkeys(records.ids, False)
+ for record in records:
+ number = record[number_fname]
+ valid, invalid, void_count = phone_sanitize_numbers_w_record([number], None, None, records, country_fname,force_format=force_format)
+ if valid:
+ res[record.id] = valid[0]
+ elif void_count:
+ res[record.id] = False
+ else:
+ res[record.id] = False
+ return res
+
+
+def phone_get_sanitized_record_number(record, number_fname='mobile', country_fname='country_id', force_format='E164'):
+ return phone_get_sanitized_records_number(record, number_fname, country_fname, force_format=force_format)[record.id]