changeset c05a19615e4c in modules/party:default
details: https://hg.tryton.org/modules/party?cmd=changeset;node=c05a19615e4c
description:
        Add ir.message and use custom exceptions

        issue3672
diffstat:

 address.py                     |  22 ++++------
 category.py                    |   2 +-
 contact_mechanism.py           |  24 +++++------
 exceptions.py                  |  28 ++++++++++++++
 message.xml                    |  40 ++++++++++++++++++++
 party.py                       |  81 +++++++++++++----------------------------
 tests/scenario_party_erase.rst |   2 +-
 tryton.cfg                     |   1 +
 8 files changed, 117 insertions(+), 83 deletions(-)

diffs (399 lines):

diff -r cba01f8cd768 -r c05a19615e4c address.py
--- a/address.py        Thu Dec 13 18:48:11 2018 +0100
+++ b/address.py        Sat Dec 29 14:20:29 2018 +0100
@@ -7,13 +7,16 @@
 from sql.conditionals import Case, Coalesce
 from sql.operators import Concat
 
+from trytond.i18n import gettext
 from trytond.model import (
     ModelView, ModelSQL, MatchMixin, DeactivableMixin, fields,
     sequence_ordered)
+from trytond.model.exceptions import AccessError
 from trytond.pyson import Eval, If
 from trytond.pool import Pool
 from trytond.transaction import Transaction
 from trytond.cache import Cache
+from .exceptions import InvalidFormat
 
 __all__ = ['Address', 'AddressFormat']
 
@@ -53,9 +56,6 @@
     def __setup__(cls):
         super(Address, cls).__setup__()
         cls._order.insert(0, ('party', 'ASC'))
-        cls._error_messages.update({
-                'write_party': 'You can not modify the party of address "%s".',
-                })
 
     @classmethod
     def __register__(cls, module_name):
@@ -204,8 +204,9 @@
             if 'party' in values:
                 for address in addresses:
                     if address.party.id != values['party']:
-                        cls.raise_user_error(
-                            'write_party', (address.rec_name,))
+                        raise AccessError(
+                            gettext('party.msg_address_change_party',
+                                address=address.rec_name))
         super(Address, cls).write(*args)
 
     @fields.depends('subdivision', 'country')
@@ -240,10 +241,6 @@
         super(AddressFormat, cls).__setup__()
         cls._order.insert(0, ('country', 'ASC'))
         cls._order.insert(1, ('language', 'ASC'))
-        cls._error_messages.update({
-                'invalid_format': ('Invalid format "%(format)s" '
-                    'with exception "%(exception)s".'),
-                })
 
     @classmethod
     def default_format_(cls):
@@ -289,10 +286,9 @@
             Template(self.format_).substitute(
                 **address._get_address_substitutions())
         except Exception as exception:
-            self.raise_user_error('invalid_format', {
-                    'format': self.format_,
-                    'exception': exception,
-                    })
+            raise InvalidFormat(gettext('party.invalid_format',
+                    format=self.format_,
+                    exception=exception)) from exception
 
     @classmethod
     def get_format(cls, address, pattern=None):
diff -r cba01f8cd768 -r c05a19615e4c category.py
--- a/category.py       Thu Dec 13 18:48:11 2018 +0100
+++ b/category.py       Sat Dec 29 14:20:29 2018 +0100
@@ -35,7 +35,7 @@
         cls._sql_constraints = [
             ('name_parent_exclude',
                 Exclude(t, (t.name, Equal), (Coalesce(t.parent, -1), Equal)),
-                'The name of a party category must be unique by parent.'),
+                'party.msg_category_name_unique'),
             ]
         cls._order.insert(0, ('name', 'ASC'))
 
diff -r cba01f8cd768 -r c05a19615e4c contact_mechanism.py
--- a/contact_mechanism.py      Thu Dec 13 18:48:11 2018 +0100
+++ b/contact_mechanism.py      Sat Dec 29 14:20:29 2018 +0100
@@ -7,9 +7,12 @@
 except ImportError:
     phonenumbers = None
 
+from trytond.i18n import gettext
 from trytond.model import (
     ModelView, ModelSQL, DeactivableMixin, fields, sequence_ordered)
+from trytond.model.exceptions import AccessError
 from trytond.pyson import Eval
+from .exceptions import InvalidPhoneNumber
 
 __all__ = ['ContactMechanism']
 
@@ -93,12 +96,6 @@
     def __setup__(cls):
         super(ContactMechanism, cls).__setup__()
         cls._order.insert(0, ('party', 'ASC'))
-        cls._error_messages.update({
-                'write_party': ('You can not modify the party of contact '
-                    'mechanism "%s".'),
-                'invalid_phonenumber': ('The phone number "%(phone)s" of '
-                    'party "%(party)s" is not valid .'),
-                })
 
     @staticmethod
     def default_type():
@@ -239,8 +236,11 @@
             if 'party' in values:
                 for mechanism in mechanisms:
                     if mechanism.party.id != values['party']:
-                        cls.raise_user_error(
-                            'write_party', (mechanism.rec_name,))
+                        raise AccessError(
+                            gettext('party'
+                            '.msg_contact_mechanism_change_party') % {
+                                'contact': mechanism.rec_name,
+                                })
         super(ContactMechanism, cls).write(*args)
         cls._format_values(all_mechanisms)
 
@@ -255,11 +255,9 @@
             return
         phonenumber = self._parse_phonenumber(self.value)
         if not (phonenumber and phonenumbers.is_valid_number(phonenumber)):
-            self.raise_user_error(
-                'invalid_phonenumber', {
-                    'phone': self.value,
-                    'party': self.party.rec_name
-                    })
+            raise InvalidPhoneNumber(
+                gettext('party.msg_invalid_phone_number',
+                    phone=self.value, party=self.party.rec_name))
 
     @classmethod
     def usages(cls, _fields=None):
diff -r cba01f8cd768 -r c05a19615e4c exceptions.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/exceptions.py     Sat Dec 29 14:20:29 2018 +0100
@@ -0,0 +1,28 @@
+# 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 trytond.exceptions import UserError, UserWarning
+from trytond.model.exceptions import ValidationError
+
+
+class InvalidIdentifierCode(ValidationError):
+    pass
+
+
+class InvalidPhoneNumber(ValidationError):
+    pass
+
+
+class VIESUnavailable(UserError):
+    pass
+
+
+class SimilarityWarning(UserWarning):
+    pass
+
+
+class EraseError(ValidationError):
+    pass
+
+
+class InvalidFormat(ValidationError):
+    pass
diff -r cba01f8cd768 -r c05a19615e4c message.xml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/message.xml       Sat Dec 29 14:20:29 2018 +0100
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tryton>
+    <data group="1">
+        <record model="ir.message" id="msg_party_code_unique">
+            <field name="text">The code on party must be unique.</field>
+        </record>
+        <record model="ir.message" id="msg_contact_mechanism_change_party">
+            <field name="text">You cannot change the party of contact 
mechanism "%(contact)s".</field>
+        </record>
+        <record model="ir.message" id="msg_invalid_phone_number">
+            <field name="text">The phone number "%(phone)s" for party 
"%(party)s" is not valid.</field>
+        </record>
+        <record model="ir.message" id="msg_invalid_vat_number">
+            <field name="text">The VAT number "%(code)s" for party "%(party)s" 
is not valid.</field>
+        </record>
+        <record model="ir.message" id="msg_vies_unavailable">
+            <field name="text">The VIES service is unavailable, try again 
later.</field>
+        </record>
+        <record model="ir.message" id="msg_different_name">
+            <field name="text">Parties have different names: "%(source_name)s" 
vs "%(destination_name)s".</field>
+        </record>
+        <record model="ir.message" id="msg_different_tax_identifier">
+            <field name="text">Parties have different tax identifiers: 
"%(source_code)s" vs "%(destination_code)s".</field>
+        </record>
+        <record model="ir.message" id="msg_erase_active_party">
+            <field name="text">Party "%(party)s" cannot be erased because they 
are still active.</field>
+        </record>
+        <record model="ir.message" id="msg_address_change_party">
+            <field name="text">You cannot change the party of address 
"%(address)s".</field>
+        </record>
+        <record model="ir.message" id="msg_invalid_format">
+            <field name="text">Invalid format "%(format)s" with exception 
"%(exception)s".</field>
+        </record>
+        <record model="ir.message" id="msg_category_name_unique">
+            <field name="text">The name of party category must be unique by 
parent.</field>
+        </record>
+    </data>
+</tryton>
diff -r cba01f8cd768 -r c05a19615e4c party.py
--- a/party.py  Thu Dec 13 18:48:11 2018 +0100
+++ b/party.py  Sat Dec 29 14:20:29 2018 +0100
@@ -5,6 +5,7 @@
 from sql import Null, Column, Literal
 from sql.functions import CharLength, Substring, Position
 
+from trytond.i18n import gettext
 from trytond.model import (ModelView, ModelSQL, MultiValueMixin, ValueMixin,
     DeactivableMixin, fields, Unique, sequence_ordered)
 from trytond.wizard import Wizard, StateTransition, StateView, Button
@@ -13,6 +14,8 @@
 from trytond.pool import Pool
 from trytond import backend
 from trytond.tools.multivalue import migrate_property
+from .exceptions import (
+    InvalidIdentifierCode, VIESUnavailable, SimilarityWarning, EraseError)
 
 __all__ = ['Party', 'PartyLang', 'PartyCategory', 'PartyIdentifier',
     'CheckVIESResult', 'CheckVIES',
@@ -76,9 +79,8 @@
         super(Party, cls).__setup__()
         t = cls.__table__()
         cls._sql_constraints = [
-            ('code_uniq', Unique(t, t.code),
-             'The code of the party must be unique.')
-        ]
+            ('code_uniq', Unique(t, t.code), 'party.msg_party_code_unique')
+            ]
         cls._order.insert(0, ('name', 'ASC'))
         cls.active.states.update({
                 'readonly': Bool(Eval('replaced_by')),
@@ -318,14 +320,6 @@
     code = fields.Char('Code', required=True)
 
     @classmethod
-    def __setup__(cls):
-        super(PartyIdentifier, cls).__setup__()
-        cls._error_messages.update({
-                'invalid_vat': ('Invalid VAT number "%(code)s" '
-                    'on party "%(party)s".'),
-                })
-
-    @classmethod
     def __register__(cls, module_name):
         pool = Pool()
         Party = pool.get('party.party')
@@ -376,10 +370,9 @@
                     party = self.party.rec_name
                 else:
                     party = ''
-                self.raise_user_error('invalid_vat', {
-                        'code': self.code,
-                        'party': party,
-                        })
+                raise InvalidIdentifierCode(
+                    gettext('party.msg_invalid_vat_number',
+                        code=self.code, party=party))
 
 
 class CheckVIESResult(ModelView):
@@ -406,14 +399,6 @@
             Button('OK', 'end', 'tryton-ok', True),
             ])
 
-    @classmethod
-    def __setup__(cls):
-        super(CheckVIES, cls).__setup__()
-        cls._error_messages.update({
-                'vies_unavailable': ('The VIES service is unavailable, '
-                    'try again later.'),
-                })
-
     def transition_check(self):
         Party = Pool().get('party.party')
 
@@ -439,7 +424,8 @@
                                 or e.faultstring.find('MS_UNAVAILABLE') \
                                 or e.faultstring.find('TIMEOUT') \
                                 or e.faultstring.find('SERVER_BUSY'):
-                            self.raise_user_error('vies_unavailable')
+                            raise VIESUnavailable(
+                                gettext('party.msg_vies_unavailable')) from e
                     raise
         self.result.parties_succeed = parties_succeed
         self.result.parties_failed = parties_failed
@@ -462,26 +448,19 @@
             ])
     replace = StateTransition()
 
-    @classmethod
-    def __setup__(cls):
-        super(PartyReplace, cls).__setup__()
-        cls._error_messages.update({
-                'different_name': ("Parties have different names: "
-                    "%(source_name)s vs %(destination_name)s."),
-                'different_tax_identifier': (
-                    "Parties have different Tax Identifier: "
-                    "%(source_code)s vs %(destination_code)s."),
-                })
-
     def check_similarity(self):
+        pool = Pool()
+        Warning = pool.get('res.user.warning')
         source = self.ask.source
         destination = self.ask.destination
         if source.name != destination.name:
             key = 'party.replace name %s %s' % (source.id, destination.id)
-            self.raise_user_warning(key, 'different_name', {
-                    'source_name': source.name,
-                    'destination_name': destination.name,
-                    })
+            if Warning.check(key):
+                raise SimilarityWarning(
+                    key,
+                    gettext('party.msg_different_name',
+                        source_name=source.name,
+                        destination_name=destination.name))
         source_code = (source.tax_identifier.code
             if source.tax_identifier else '')
         destination_code = (destination.tax_identifier.code
@@ -489,10 +468,12 @@
         if source_code != destination_code:
             key = 'party.replace tax_identifier %s %s' % (
                 source.id, destination.id)
-            self.raise_user_warning(key, 'different_tax_identifier', {
-                    'source_code': source_code,
-                    'destination_code': destination_code,
-                    })
+            if Warning.check(key):
+                raise SimilarityWarning(
+                    key,
+                    gettext('party.msg_different_tax_identifier',
+                        source_code=source_code,
+                        destination_code=destination_code))
 
     def transition_replace(self):
         pool = Pool()
@@ -582,15 +563,6 @@
             ])
     erase = StateTransition()
 
-    @classmethod
-    def __setup__(cls):
-        super(PartyErase, cls).__setup__()
-        cls._error_messages.update({
-                'active_party': (
-                    'The party "%(party)s" can not be erased '
-                    'because he is still active.'),
-                })
-
     def transition_erase(self):
         pool = Pool()
         Party = pool.get('party.party')
@@ -662,9 +634,8 @@
 
     def check_erase(self, party):
         if party.active:
-            self.raise_user_error('active_party', {
-                    'party': party.rec_name,
-                    })
+            raise EraseError(gettext('party.msg_erase_active_party',
+                    party=party.rec_name))
 
     def to_erase(self, party_id):
         pool = Pool()
diff -r cba01f8cd768 -r c05a19615e4c tests/scenario_party_erase.rst
--- a/tests/scenario_party_erase.rst    Thu Dec 13 18:48:11 2018 +0100
+++ b/tests/scenario_party_erase.rst    Sat Dec 29 14:20:29 2018 +0100
@@ -38,7 +38,7 @@
     >>> erase.execute('erase')  # doctest: +IGNORE_EXCEPTION_DETAIL
     Traceback (most recent call last):
         ...
-    UserError: ...
+    EraseError: ...
 
 Erase inactive party::
 
diff -r cba01f8cd768 -r c05a19615e4c tryton.cfg
--- a/tryton.cfg        Thu Dec 13 18:48:11 2018 +0100
+++ b/tryton.cfg        Sat Dec 29 14:20:29 2018 +0100
@@ -10,3 +10,4 @@
     address.xml
     contact_mechanism.xml
     configuration.xml
+    message.xml

Reply via email to