details:   https://code.tryton.org/tryton/commit/55a07a868730
branch:    default
user:      Cédric Krier <[email protected]>
date:      Thu Apr 23 09:18:59 2026 +0200
description:
        Guess the type of contact mechanism

        Closes #14768
diffstat:

 modules/party/CHANGELOG                                                |   1 +
 modules/party/contact_mechanism.py                                     |  36 
+++++++++-
 modules/party/tests/scenario_party_contact_mechanism_notifications.rst |   2 +-
 modules/party/view/contact_mechanism_form.xml                          |   4 +-
 modules/party/view/contact_mechanism_tree.xml                          |   2 +-
 modules/party/view/contact_mechanism_tree_sequence.xml                 |   2 +-
 6 files changed, 41 insertions(+), 6 deletions(-)

diffs (134 lines):

diff -r 4b7edc0b4b00 -r 55a07a868730 modules/party/CHANGELOG
--- a/modules/party/CHANGELOG   Thu Apr 23 09:19:13 2026 +0200
+++ b/modules/party/CHANGELOG   Thu Apr 23 09:18:59 2026 +0200
@@ -1,3 +1,4 @@
+* Guess the type of contact mechanism
 
 Version 8.0.0 - 2026-04-20
 --------------------------
diff -r 4b7edc0b4b00 -r 55a07a868730 modules/party/contact_mechanism.py
--- a/modules/party/contact_mechanism.py        Thu Apr 23 09:19:13 2026 +0200
+++ b/modules/party/contact_mechanism.py        Thu Apr 23 09:18:59 2026 +0200
@@ -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 @@
     'fax',
     }
 
+_URL_REGEX = re.compile(r'^(http|ftp)s?://', re.IGNORECASE)
+
 
 class _ContactMechanismMixin:
     __slots__ = ()
@@ -140,7 +144,7 @@
 
     @staticmethod
     def default_type():
-        return 'phone'
+        return 'other'
 
     @classmethod
     def default_party(cls):
@@ -219,9 +223,39 @@
         #  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 -r 4b7edc0b4b00 -r 55a07a868730 
modules/party/tests/scenario_party_contact_mechanism_notifications.rst
--- a/modules/party/tests/scenario_party_contact_mechanism_notifications.rst    
Thu Apr 23 09:19:13 2026 +0200
+++ b/modules/party/tests/scenario_party_contact_mechanism_notifications.rst    
Thu Apr 23 09:18:59 2026 +0200
@@ -42,7 +42,7 @@
 
 Change contact mechanism type::
 
-    >>> contact_mechanism.type = 'other'
+    >>> contact_mechanism.type = 'jabber'
     >>> contact_mechanism.value = "[email protected]"
 
 Check notifications::
diff -r 4b7edc0b4b00 -r 55a07a868730 
modules/party/view/contact_mechanism_form.xml
--- a/modules/party/view/contact_mechanism_form.xml     Thu Apr 23 09:19:13 
2026 +0200
+++ b/modules/party/view/contact_mechanism_form.xml     Thu Apr 23 09:18:59 
2026 +0200
@@ -12,8 +12,6 @@
         <label name="sequence"/>
         <field name="sequence"/>
     </group>
-    <label name="type"/>
-    <field name="type"/>
     <group col="2" colspan="2" id="value">
         <label name="other_value"/>
         <field name="other_value"/>
@@ -26,6 +24,8 @@
         <label name="sip"/>
         <field name="sip" widget="sip"/>
     </group>
+    <label name="type"/>
+    <field name="type"/>
     <label name="name"/>
     <field name="name"/>
     <label name="language"/>
diff -r 4b7edc0b4b00 -r 55a07a868730 
modules/party/view/contact_mechanism_tree.xml
--- a/modules/party/view/contact_mechanism_tree.xml     Thu Apr 23 09:19:13 
2026 +0200
+++ b/modules/party/view/contact_mechanism_tree.xml     Thu Apr 23 09:18:59 
2026 +0200
@@ -2,7 +2,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. -->
 <tree>
-    <field name="type"/>
+    <field name="type" optional="0"/>
     <field name="value" expand="1"/>
     <field name="name" expand="1" optional="0"/>
     <field name="party" expand="2" optional="0"/>
diff -r 4b7edc0b4b00 -r 55a07a868730 
modules/party/view/contact_mechanism_tree_sequence.xml
--- a/modules/party/view/contact_mechanism_tree_sequence.xml    Thu Apr 23 
09:19:13 2026 +0200
+++ b/modules/party/view/contact_mechanism_tree_sequence.xml    Thu Apr 23 
09:18:59 2026 +0200
@@ -2,7 +2,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. -->
 <tree sequence="sequence" editable="1">
-    <field name="type"/>
+    <field name="type" optional="0"/>
     <field name="value" expand="1"/>
     <field name="name" expand="1" optional="0"/>
     <field name="party" expand="2" optional="0"/>

Reply via email to