changeset cba01f8cd768 in modules/party:default
details: https://hg.tryton.org/modules/party?cmd=changeset;node=cba01f8cd768
description:
Use country code as local prefix to parse phone numbers
issue7831
review52521002
diffstat:
CHANGELOG | 2 +
contact_mechanism.py | 44 +++++++++++++++++++++-------------
tests/scenario_party_phone_number.rst | 41 ++++++++++++++++++++++++++++++++
tests/test_party.py | 5 +++
4 files changed, 75 insertions(+), 17 deletions(-)
diffs (149 lines):
diff -r 77dc19b2db36 -r cba01f8cd768 CHANGELOG
--- a/CHANGELOG Mon Oct 15 15:53:48 2018 +0200
+++ b/CHANGELOG Thu Dec 13 18:48:11 2018 +0100
@@ -1,3 +1,5 @@
+* Use country code as local prefix to parse phone numbers
+
Version 5.0.0 - 2018-10-01
* Bug fixes (see mercurial logs for details)
* Support attention party in address format
diff -r 77dc19b2db36 -r cba01f8cd768 contact_mechanism.py
--- a/contact_mechanism.py Mon Oct 15 15:53:48 2018 +0200
+++ b/contact_mechanism.py Thu Dec 13 18:48:11 2018 +0100
@@ -1,5 +1,6 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
+from itertools import chain
try:
import phonenumbers
from phonenumbers import PhoneNumberFormat, NumberParseException
@@ -126,26 +127,37 @@
return 'fax:%s' % value
return None
- @classmethod
- def format_value(cls, value=None, type_=None):
- if phonenumbers and type_ in _PHONE_TYPES:
+ @fields.depends('party', '_parent_party.addreses')
+ def _phone_country_codes(self):
+ if self.party:
+ for address in self.party.addresses:
+ if address.country:
+ yield address.country.code
+
+ @fields.depends(methods=['_phone_country_codes'])
+ def _parse_phonenumber(self, value):
+ for country_code in chain(self._phone_country_codes(), [None]):
try:
- phonenumber = phonenumbers.parse(value)
+ # Country code is ignored if value has an international prefix
+ return phonenumbers.parse(value, country_code)
except NumberParseException:
pass
- else:
+ return None
+
+ @fields.depends(methods=['_parse_phonenumber'])
+ def format_value(self, value=None, type_=None):
+ if phonenumbers and type_ in _PHONE_TYPES:
+ phonenumber = self._parse_phonenumber(value)
+ if phonenumber:
value = phonenumbers.format_number(
phonenumber, PhoneNumberFormat.INTERNATIONAL)
return value
- @classmethod
- def format_value_compact(cls, value=None, type_=None):
+ @fields.depends(methods=['_parse_phonenumber'])
+ def format_value_compact(self, value=None, type_=None):
if phonenumbers and type_ in _PHONE_TYPES:
- try:
- phonenumber = phonenumbers.parse(value)
- except NumberParseException:
- pass
- else:
+ phonenumber = self._parse_phonenumber(value)
+ if phonenumber:
value = phonenumbers.format_number(
phonenumber, PhoneNumberFormat.E164)
return value
@@ -155,7 +167,8 @@
# Setting value is done by on_changes
pass
- @fields.depends(methods=['on_change_with_url'])
+ @fields.depends(
+ methods=['on_change_with_url', 'format_value', 'format_value_compact'])
def _change_value(self, value, type_):
self.value = self.format_value(value=value, type_=type_)
self.value_compact = self.format_value_compact(
@@ -240,10 +253,7 @@
def check_valid_phonenumber(self):
if not phonenumbers or self.type not in _PHONE_TYPES:
return
- try:
- phonenumber = phonenumbers.parse(self.value)
- except NumberParseException:
- phonenumber = None
+ phonenumber = self._parse_phonenumber(self.value)
if not (phonenumber and phonenumbers.is_valid_number(phonenumber)):
self.raise_user_error(
'invalid_phonenumber', {
diff -r 77dc19b2db36 -r cba01f8cd768 tests/scenario_party_phone_number.rst
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/scenario_party_phone_number.rst Thu Dec 13 18:48:11 2018 +0100
@@ -0,0 +1,41 @@
+===========================
+Party Phone Number Scenario
+===========================
+
+Imports::
+
+ >>> from proteus import Model, Wizard
+ >>> from trytond.tests.tools import activate_modules
+
+Install party::
+
+ >>> config = activate_modules('party')
+
+Create a country::
+
+ >>> Country = Model.get('country.country')
+ >>> spain = Country(name='Spain', code='ES')
+ >>> spain.save()
+
+Create a party related to the country::
+
+ >>> Party = Model.get('party.party')
+ >>> party = Party(name='Pam')
+ >>> address, = party.addresses
+ >>> address.country = spain
+
+The country phone prefix is set when creating a phone of this party::
+
+ >>> local_phone = party.contact_mechanisms.new()
+ >>> local_phone.type = 'phone'
+ >>> local_phone.value = '666666666'
+ >>> local_phone.value
+ '+34 666 66 66 66'
+
+The phone prefix is respected when using international prefix::
+
+ >>> international_phone = party.contact_mechanisms.new()
+ >>> international_phone.type = 'phone'
+ >>> international_phone.value = '+442083661178'
+ >>> international_phone.value
+ '+44 20 8366 1178'
diff -r 77dc19b2db36 -r cba01f8cd768 tests/test_party.py
--- a/tests/test_party.py Mon Oct 15 15:53:48 2018 +0200
+++ b/tests/test_party.py Thu Dec 13 18:48:11 2018 +0100
@@ -428,4 +428,9 @@
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
+ suite.addTests(doctest.DocFileSuite(
+ 'scenario_party_phone_number.rst',
+ tearDown=doctest_teardown, encoding='utf-8',
+ checker=doctest_checker,
+ optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
return suite