diff --git a/modules/party/CHANGELOG b/modules/party/CHANGELOG
index 3fa8a73b42..ce925ce916 100644
--- a/modules/party/CHANGELOG
+++ b/modules/party/CHANGELOG
@@ -1,3 +1,4 @@
+* Guess the type of contact mechanism
Version 8.0.0 - 2026-04-20
--------------------------
diff --git a/modules/party/contact_mechanism.py b/modules/party/contact_mechanism.py
index d0329048dd..6b5f41fd2c 100644
--- a/modules/party/contact_mechanism.py
+++ b/modules/party/contact_mechanism.py
@@ -1,5 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
+
+import re
from itertools import chain
try:
@@ -39,6 +41,8 @@ _PHONE_TYPES = {
'fax',
}
+_URL_REGEX = re.compile(r'^(http|ftp)s?://', re.IGNORECASE)
+
class _ContactMechanismMixin:
__slots__ = ()
@@ -140,7 +144,7 @@ class ContactMechanism(
@staticmethod
def default_type():
- return 'phone'
+ return 'other'
@classmethod
def default_party(cls):
@@ -219,9 +223,39 @@ class ContactMechanism(
# Setting value is done by on_changes
pass
+ def _guess_types(self, value, type_):
+ types = []
+ if type_ in {'skype', 'sip', 'irc', 'jabber'}:
+ return types
+ if phonenumbers:
+ if phonenumber := self._parse_phonenumber(value):
+ phonenumber_type = phonenumbers.number_type(phonenumber)
+ if phonenumber_type in {
+ phonenumbers.PhoneNumberType.FIXED_LINE}:
+ types.append('phone')
+ elif phonenumber_type in {
+ phonenumbers.PhoneNumberType.MOBILE}:
+ types.append('mobile')
+ else:
+ types.extend(_PHONE_TYPES)
+ try:
+ validate_email(value, check_deliverability=False)
+ except EmailNotValidError:
+ pass
+ else:
+ types.append('email')
+ if re.match(_URL_REGEX, value):
+ types.append('website')
+ return types
+
@fields.depends(
methods=['on_change_with_url', 'format_value', 'format_value_compact'])
def _change_value(self, value, type_):
+ if value:
+ guess_types = self._guess_types(value, type_)
+ if guess_types and type_ not in guess_types:
+ self.type = type_ = guess_types[0]
+
self.value = self.format_value(value=value, type_=type_)
self.value_compact = self.format_value_compact(
value=value, type_=type_)
diff --git a/modules/party/tests/scenario_party_contact_mechanism_notifications.rst b/modules/party/tests/scenario_party_contact_mechanism_notifications.rst
index 5c50bb6dea..15a8af45c1 100644
--- a/modules/party/tests/scenario_party_contact_mechanism_notifications.rst
+++ b/modules/party/tests/scenario_party_contact_mechanism_notifications.rst
@@ -42,7 +42,7 @@ Check notifications::
Change contact mechanism type::
- >>> contact_mechanism.type = 'other'
+ >>> contact_mechanism.type = 'jabber'
>>> contact_mechanism.value = "test@example.com"
Check notifications::
diff --git a/modules/party/view/contact_mechanism_form.xml b/modules/party/view/contact_mechanism_form.xml
index 178fc024e9..461c7cb24a 100644
--- a/modules/party/view/contact_mechanism_form.xml
+++ b/modules/party/view/contact_mechanism_form.xml
@@ -12,8 +12,6 @@ this repository contains the full copyright notices and license terms. -->
-
-
@@ -26,6 +24,8 @@ this repository contains the full copyright notices and license terms. -->
+
+
diff --git a/modules/party/view/contact_mechanism_tree.xml b/modules/party/view/contact_mechanism_tree.xml
index a3868fe404..c753aa7784 100644
--- a/modules/party/view/contact_mechanism_tree.xml
+++ b/modules/party/view/contact_mechanism_tree.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/modules/party/view/contact_mechanism_tree_sequence.xml b/modules/party/view/contact_mechanism_tree_sequence.xml
index b2432faabb..01dfc11915 100644
--- a/modules/party/view/contact_mechanism_tree_sequence.xml
+++ b/modules/party/view/contact_mechanism_tree_sequence.xml
@@ -2,7 +2,7 @@
-
+