From 0d1da7c1b421d77bd637d2d311d46c9e939caff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Sat, 25 Jan 2025 13:21:34 +0100 Subject: [PATCH] Add structured address --- modules/party/CHANGELOG | 2 + modules/party/address.py | 290 +- modules/party/address.xml | 2683 +++++++++++++++--- modules/party/party.py | 8 +- modules/party/tests/test_module.py | 54 + modules/party/view/address_form.xml | 35 +- modules/party/view/address_form_simple.xml | 36 +- modules/party/view/address_format_form.xml | 16 + modules/party/view/address_tree.xml | 1 - modules/party/view/address_tree_sequence.xml | 1 - 10 files changed, 2774 insertions(+), 352 deletions(-) diff --git a/modules/party/CHANGELOG b/modules/party/CHANGELOG index aedbaf1dba..a2bda70f5c 100644 --- a/modules/party/CHANGELOG +++ b/modules/party/CHANGELOG @@ -1,3 +1,5 @@ +* Add structured address +* Rename address name to building name * Remove support for Python 3.8 * Add support for Python 3.13 * Notify for duplicate contact mechanism diff --git a/modules/party/address.py b/modules/party/address.py index 31afa8a5e5..9679611a01 100644 --- a/modules/party/address.py +++ b/modules/party/address.py @@ -1,6 +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. 'Address' +import re from string import Template from sql import Literal @@ -33,8 +34,84 @@ class Address( party_name = fields.Char( "Party Name", help="If filled, replace the name of the party for address formatting") - name = fields.Char("Building Name") - street = fields.Text("Street") + + street = fields.Function(fields.Text( + "Street", + states={ + 'readonly': ( + Eval('street_name') + | Eval('building_number') + | Eval('unit_number') + | Eval('floor_number') + | Eval('room_number') + | Eval('post_box') + | Eval('post_office') + | Eval('private_bag')), + }), + 'on_change_with_street', setter='set_street', searcher='search_street') + street_unstructured = fields.Text( + "Street", + states={ + 'invisible': ( + (Eval('street_name') + | Eval('building_number') + | Eval('unit_number') + | Eval('floor_number') + | Eval('room_number') + | Eval('post_box') + | Eval('post_office') + | Eval('private_bag')) + & ~Eval('street_unstructured')), + }) + + street_name = fields.Char( + "Street Name", + states={ + 'invisible': Eval('street_unstructured') & ~Eval('street_name'), + }) + building_name = fields.Char( + "Building Name", + states={ + 'invisible': Eval('street_unstructured') & ~Eval('building_name'), + }) + building_number = fields.Char( + "Building Number", + states={ + 'invisible': ( + Eval('street_unstructured') & ~Eval('building_number')), + }) + unit_number = fields.Char( + "Unit Number", + states={ + 'invisible': Eval('street_unstructured') & ~Eval('unit_number'), + }) + floor_number = fields.Char( + "Floor Number", + states={ + 'invisible': Eval('street_unstructured') & ~Eval('floor_number'), + }) + room_number = fields.Char( + "Room Number", + states={ + 'invisible': Eval('street_unstructured') & ~Eval('room_number'), + }) + + post_box = fields.Char( + "Post Box", + states={ + 'invisible': Eval('street_unstructured') & ~Eval('post_box'), + }) + private_bag = fields.Char( + "Private Bag", + states={ + 'invisible': Eval('street_unstructured') & ~Eval('private_bag'), + }) + post_office = fields.Char( + "Post Office", + states={ + 'invisible': Eval('street_unstructured') & ~Eval('post_office'), + }) + street_single_line = fields.Function( fields.Char("Street"), 'on_change_with_street_single_line', @@ -79,6 +156,17 @@ class Address( autocomplete_city=RPC(instantiate=0, cache=dict(days=1)), ) + @classmethod + def __register__(cls, module_name): + table = cls.__table_handler__(module_name) + + # Migration from 7.4: rename street to street_unstructured + # and name to building_name + table.column_rename('street', 'street_unstructured') + table.column_rename('name', 'building_name') + + super().__register__(module_name) + @fields.depends('street') def on_change_with_street_single_line(self, name=None): if self.street: @@ -137,8 +225,7 @@ class Address( AddressFormat = pool.get('party.address.format') full_address = Template(AddressFormat.get_format(self)).substitute( **self._get_address_substitutions()) - return '\n'.join( - filter(None, (x.strip() for x in full_address.splitlines()))) + return self._strip(full_address) def _get_address_substitutions(self): pool = Pool() @@ -157,7 +244,6 @@ class Address( substitutions = { 'party_name': '', 'attn': '', - 'name': getattr(self, 'name', None) or '', 'street': getattr(self, 'street', None) or '', 'postal_code': getattr(self, 'postal_code', None) or '', 'city': getattr(self, 'city', None) or '', @@ -179,8 +265,102 @@ class Address( context['address_attention_party'].full_name) for key, value in list(substitutions.items()): substitutions[key.upper()] = value.upper() + substitutions.update(self._get_street_substitutions()) return substitutions + @fields.depends('street', 'street_unstructured') + def on_change_street(self): + self.street_unstructured = self.street + + @fields.depends( + 'street_unstructured', 'country', + methods=['_get_street_substitutions']) + def on_change_with_street(self, name=None): + pool = Pool() + AddressFormat = pool.get('party.address.format') + + format_ = AddressFormat.get_street_format(self) + street = Template(format_).substitute( + **self._get_street_substitutions()) + if not (street := self._strip(street, doublespace=True)): + street = self.street_unstructured + return street + + @classmethod + def set_street(cls, addresses, name, value): + addresses = [a for a in addresses if a.street != value] + cls.write(addresses, { + 'street_unstructured': value, + 'street_name': None, + 'building_name': None, + 'building_number': None, + 'unit_number': None, + 'floor_number': None, + 'room_number': None, + }) + + @classmethod + def search_street(cls, name, clause): + if clause[1].startswith('!') or clause[1].startswith('not '): + bool_op = 'AND' + else: + bool_op = 'OR' + return [bool_op, + ('street_unstructured', *clause[1:]), + ('street_name', *clause[1:]), + ('building_name', *clause[1:]), + ('building_number', *clause[1:]), + ('unit_number', *clause[1:]), + ('floor_number', *clause[1:]), + ('room_number', *clause[1:]), + ] + + @fields.depends( + 'country', 'street_name', 'building_number', 'unit_number', + 'floor_number', 'room_number', 'post_box', 'private_bag', + 'post_office') + def _get_street_substitutions(self): + pool = Pool() + AddressFormat = pool.get('party.address.format') + + substitutions = { + 'street_name': getattr(self, 'street_name', None) or '', + 'building_name': getattr(self, 'building_name', None) or '', + 'building_number': getattr(self, 'building_number', None) or '', + 'unit_number': getattr(self, 'unit_number', None) or '', + 'floor_number': getattr(self, 'floor_number', None) or '', + 'room_number': getattr(self, 'room_number', None) or '', + 'post_box': getattr(self, 'post_box', None) or '', + 'private_bag': getattr(self, 'private_bag', None) or '', + 'post_office': getattr(self, 'post_office', None) or '', + } + for number in [ + 'building_number', + 'unit_number', + 'floor_number', + 'room_number', + 'post_box', + 'private_bag', + 'post_office', + ]: + if (substitutions[number] + and (format_ := AddressFormat.get_number_format( + number, self))): + substitutions[number] = format_.format(substitutions[number]) + for key, value in list(substitutions.items()): + substitutions[key.upper()] = value.upper() + return substitutions + + @classmethod + def _strip(cls, value, doublespace=False): + value = re.sub( + r'[\,\/,–][\s,\,\/]*([\,\/,–])', r'\1', value, flags=re.MULTILINE) + if doublespace: + value = re.sub(r' {1,}', r' ', value, flags=re.MULTILINE) + value = value.splitlines() + value = map(lambda x: x.strip(' ,/–'), value) + return '\n'.join(filter(None, value)) + @property def party_full_name(self): name = '' @@ -203,7 +383,6 @@ class Address( return ', '.join( filter(None, [ party, - self.name, street, self.postal_code, self.city, @@ -217,7 +396,6 @@ class Address( bool_op = 'OR' return [bool_op, ('party',) + tuple(clause[1:]), - ('name',) + tuple(clause[1:]), ('street',) + tuple(clause[1:]), ('postal_code',) + tuple(clause[1:]), ('city',) + tuple(clause[1:]), @@ -267,9 +445,8 @@ class AddressFormat(DeactivableMixin, MatchMixin, ModelSQL, ModelView): country_code = fields.Char("Country Code", size=2) language_code = fields.Char("Language Code", size=2) format_ = fields.Text("Format", required=True, - help="Available variables (also in upper case):\n" + help="Available variables (also in upper case and street variables):\n" "- ${party_name}\n" - "- ${name}\n" "- ${attn}\n" "- ${street}\n" "- ${postal_code}\n" @@ -278,6 +455,39 @@ class AddressFormat(DeactivableMixin, MatchMixin, ModelSQL, ModelView): "- ${subdivision_code}\n" "- ${country}\n" "- ${country_code}") + street_format = fields.Text("Street Format", required=True, + help="Available variables (also in upper case):\n" + "- ${street_name}\n" + "- ${building_name}\n" + "- ${building_number}\n" + "- ${unit_number}\n" + "- ${floor_number}\n" + "- ${room_number}\n" + "- ${post_box}\n" + "- ${private_bag}\n" + "- ${post_office}\n") + building_number_format = fields.Char( + "Building Number Format", + help="Use {} as placeholder for the number.") + unit_number_format = fields.Char( + "Unit Number Format", + help="Use {} as placeholder for the number.") + floor_number_format = fields.Char( + "Floor Number Format", + help="Use {} as placeholder for the number.") + room_number_format = fields.Char( + "Room Number Format", + help="Use {} as placeholder for the number.") + + post_box_format = fields.Char( + "Post Box Format", + help="Use {} as placeholder for the number.") + private_bag_format = fields.Char( + "Post Box Format", + help="Use {} as placeholder for the number.") + post_office_format = fields.Char( + "Post Box Format", + help="Use {} as placeholder for the number.") _get_format_cache = Cache('party.address.format.get_format') @@ -291,7 +501,6 @@ class AddressFormat(DeactivableMixin, MatchMixin, ModelSQL, ModelView): def default_format_(cls): return """${attn} ${party_name} -${name} ${street} ${postal_code} ${city} ${subdivision} @@ -302,10 +511,19 @@ ${COUNTRY}""" super().on_modification(mode, formats, field_names=field_names) cls._get_format_cache.clear() + @classmethod + def default_street_format(cls): + return ( + "${street_name} ${building_name} ${building_number}" + "/${unit_number}/${floor_number}/${room_number}\n" + "${post_box} ${private_bag} ${post_office}") + @classmethod def validate_fields(cls, formats, field_names): super().validate_fields(formats, field_names) cls.check_format(formats, field_names) + cls.check_street_format(formats, field_names) + cls.check_number_format(formats, field_names) @classmethod def check_format(cls, formats, field_names=None): @@ -323,8 +541,54 @@ ${COUNTRY}""" format=format_.format_, exception=exception)) from exception + @classmethod + def check_street_format(cls, formats, field_names=None): + pool = Pool() + Address = pool.get('party.address') + if field_names and 'street_format' not in field_names: + return + address = Address() + substitutions = address._get_street_substitutions() + for format_ in formats: + try: + Template(format_.street_format).substitute(**substitutions) + except Exception as exception: + raise InvalidFormat(gettext('party.msg_invalid_format', + format=format_.street_format, + exception=exception)) from exception + + @classmethod + def check_number_format(cls, formats, field_names=None): + fields = [ + 'building_number_format', 'floor_number_format', + 'unit_number_format', 'room_number_format', + 'post_box_format', 'private_bag_format', 'post_office_format'] + if field_names and not (field_names & set(fields)): + return + for format_ in formats: + for field in fields: + if number_format := getattr(format_, field): + try: + number_format.format('') + except Exception as exception: + raise InvalidFormat(gettext('party.msg_invalid_format', + format=number_format, + exception=exception)) from exception + @classmethod def get_format(cls, address, pattern=None): + return cls._get_format('format_', address, pattern=pattern) + + @classmethod + def get_street_format(cls, address, pattern=None): + return cls._get_format('street_format', address, pattern=pattern) + + @classmethod + def get_number_format(cls, number, address, pattern=None): + return cls._get_format(f'{number}_format', address, pattern=pattern) + + @classmethod + def _get_format(cls, field, address, pattern=None): if pattern is None: pattern = {} else: @@ -333,17 +597,17 @@ ${COUNTRY}""" 'country_code', address.country.code if address.country else None) pattern.setdefault('language_code', Transaction().language[:2]) - key = tuple(sorted(pattern.items())) + key = (field, *sorted(pattern.items())) format_ = cls._get_format_cache.get(key) if format_ is not None: return format_ for record in cls.search([]): if record.match(pattern): - format_ = record.format_ + format_ = getattr(record, field) break else: - format_ = cls.default_format_() + format_ = getattr(cls, f'default_{field}', lambda: '')() cls._get_format_cache.set(key, format_) return format_ diff --git a/modules/party/address.xml b/modules/party/address.xml index 4be7d7fb06..aa9868368a 100644 --- a/modules/party/address.xml +++ b/modules/party/address.xml @@ -147,85 +147,379 @@ this repository contains the full copyright notices and license terms. --> - + + + + AF + ${attn} ${party_name} +${street} +${city} +${subdivision} +${postal_code} +${COUNTRY} + ${street_name} +${building_number} + House No. {} + + + + AD + ES + ${party_name} +${attn} +${STREET} +${postal_code} ${CITY} +${COUNTRY} + ${unit_number} ${floor_number} ${room_number} +${building_name} +${street_name} ${building_number} + AP {} + + + + AD + + ${party_name} +${attn} +${STREET} +${POSTAL_CODE} ${CITY} +${COUNTRY} + ${unit_number} ${floor_number} ${room_number} +${building_name} +${building_number} ${street_name} +${post_box} + BP {} + + + + AE + ${party_name} +${street} +${CITY} +${COUNTRY} + ${post_box} + PO BOX {} + + + + AI + ${party_name} +${street} +${city} +${COUNTRY_CODE}-${postal_code} +${COUNTRY} + ${unit_number} + P.O. {} + + + + AL + ${party_name} +${street} +${postal_code} +${city} +${subdivision} +${COUNTRY} + ${street_name} +${building_number} ${floor_number} ${room_number} + Pallati {} + Shkalla {} + Apartamenti {} + + + + AM + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number} ${unit_number} + apt {} + + + + AO + ${party_name} +${street} +${city} +${COUNTRY} + ${street_name} ${building_number}–${floor_number} + {}o + + AR ${party_name} -${name} +${attn} ${street} -${subdivision} ${POSTAL_CODE}, ${city} ${COUNTRY} - - - - AU - ${party_name} -${attn} -${name} -${street} -${CITY} ${SUBDIVISION} ${POSTAL_CODE} -${COUNTRY} + ${street_name} ${building_number} +${floor_number} ${room_number} +${post_box} +${post_office} + CASILLA DE CORREOS {} AT ${party_name} ${attn} -${name} ${street} -${postal_code} ${city} +${postal_code} ${CITY} ${COUNTRY} + ${street_name} ${building_number}/${unit_number}/${room_number} + + + + AU + ${party_name} +${attn} +${street} +${CITY} ${SUBDIVISION_CODE} ${POSTAL_CODE} +${COUNTRY} + ${building_name} +${room_number}/${floor_number}/${unit_number}/${building_number} ${street_name} +${post_box} + PO BOX {} + + + + AW + ${party_name} +${street} +${city} +${COUNTRY} + ${building_name} +${street_name} ${building_number} + #{} + + + + AZ + ${party_name} +${street} +${COUNTRY_CODE}${postal_code} ${city} +${subdivision} +${COUNTRY} + ${street_name} ${building_number} +${post_box} + a/q {} + + + + BA + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${building_name} +${street_name} ${building_number} + + + + BB + ${party_name} +${street} +${city} ${COUNTRY_CODE}${postal_code} +${COUNTRY} + ${building_number} +${street_name} +${building_name} + #{} BD ${party_name} -${attn} -${name} ${street} -${city}-${postal_code} -${COUNTRY} - - - - BY - ${party_name} -${name} -${street} -${postal_code}, ${city} -${subdivision} +${CITY} - ${postal_code} ${COUNTRY} + ${unit_number}/${floor_number}/${room_number} ${building_name} +${street_name} ${building_number} BE ${attn} ${party_name} -${name} ${street} ${postal_code} ${city} ${COUNTRY} + ${building_name} +${street_name} ${building_number} ${unit_number} +${post_box} + box {} + bpack {} - - BR + + BF ${party_name} ${street} -${name} -${city} - ${subdivision_code} -${postal_code} +${postal_code} ${CITY} ${COUNTRY} + ${building_name} +${building_number} ${street_name} +${post_box} ${post_office} + BP {} BG ${party_name} ${street} -${name} -${postal_code} ${city} +${postal_code} ${CITY} +${SUBDIVISION} +${COUNTRY} + ${street_name} ${building_number}, ${unit_number}, ${floor_number}, ${room_number} +${building_name} + No. {} + бл. {} + ет. {} + ап. {} + + + + BH + ${party_name} +${street} +${CITY} ${postal_code} +${COUNTRY} + ${building_number} +${street_name} +${post_box} + House {} + P.O Box {} + + + + BI + ${party_name} +${street} +${CITY} +${COUNTRY} + ${post_box} + BP {} + + + + BJ + ${party_name} +${street} +${CITY} +${COUNTRY} + ${building_number} ${street_name} + + + + BM + ${party_name} +${street} +${CITY} ${POSTAL_CODE} +${COUNTRY} + ${building_number} +${unit_number} +${building_number} ${street_name} +${post_box} + PO Box {} + + + + BN + ${PARTY_NAME} +${STREET} +${CITY} +${SUBDIVISION} ${POSTAL_CODE} +${COUNTRY} + ${building_number}, ${floor_number}, ${street_name} + + + + BO + ${attn} +${party_name} +${street} +${CITY} +BOLIVIA + ${STREET_NAME} ${BUILDING_NUMBER} +${building_name} +${post_box} + Casilla Postal {} + + + + BR + ${party_name} +${street} +${CITY} - ${SUBDIVISION_CODE} +${postal_code} +${COUNTRY} + ${street_name}, ${building_number}, ${unit_number}/${floor_number}/${room_number} +${building_name} + + + + BS + ${party_name} +${street} +${city} +${COUNTRY} + ${post_office} ${post_box} + P.O. Box {} + + + + BT + ${party_name} +${street} +${city} ${postal_code} +${COUNTRY} + ${street_name}, ${building_number} +${unit_number} +${room_number} +${building_name} +${post_box} +${post_office} + House No. {} + Flat No. {} + P.O Box {} + + + + BW + ${party_name} +${street} +${CITY} +${COUNTRY} + ${post_box} +${private_bag} + P.O. Box {} + P/Bag {} + + + + BY + ${party_name} +${street} +${postal_code}, ${city} ${subdivision} ${COUNTRY} + ${street_name}, ${building_number}, ${unit_number}, ${floor_number}, ${room_number} + d. {} + bud. {} + kv. {} + + + + BZ + ${party_name} +${street} +${CITY} +${COUNTRY} + ${building_number} ${street_name} ${room_number} + Apt {} @@ -233,53 +527,194 @@ ${COUNTRY} fr ${attn} ${party_name} -${name} ${street} ${city} (${subdivision}) ${postal_code} ${COUNTRY} + ${building_name} +${unit_number}–${building_number}, ${street_name} CA ${ATTN} ${PARTY_NAME} -${NAME} ${STREET} ${CITY} ${SUBDIVISION_CODE} ${POSTAL_CODE} ${COUNTRY} + ${building_name} +${unit_number}–${building_number} ${street_name} +${post_box} ${post_office} + PO BOX {} + + + + CD + ${party_name} +${street} +${CITY} +${postal_code} ${SUBDIVISION} +CONGO (REP.) + ${street_name} ${building_number} +${post_box} + N°{} + B.P {} + + + + CF + ${attn} +${party_name} +${street} +${CITY} +${COUNTRY} + ${post_box} + BP {} + + + + CG + ${party_name} +${street} +${CITY} +${COUNTRY} + ${building_number}, ${street_name} + + + + CH + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number} +${post_box} + Case postale {} + + + + CI + ${attn} +${party_name} +${street_name} +${post_office} ${street} ${CITY} ${post_office} +${COUNTRY} + ${post_box} + B.P. {} + + + + CK + ${party_name} +${street}, ${city} +${SUBDIVISION} +${COUNTRY} + ${post_box} +${street_name} + PO Box {} CL + ${attn} +${party_name} +${street} +${postal_code} ${CITY} +${SUBDIVISION} +${COUNTRY} + ${street_name} ${building_number}, ${unit_number}, ${floor_number}, ${room_number} +${building_name} + N° {} + Dep. {} + Piso {} + + + + CM ${party_name} ${street} -${name} -${postal_code} -${city} +${CITY} ${COUNTRY} + ${post_box} + BP {} CN zh ${COUNTRY} ${POSTAL_CODE} -${subdivision}${city}${street}${name} +${subdivision}${city}${street} ${party_name} + ${building_number}${unit_number}${floor_number}${room_number}${building_name} CN - ${COUNTRY} ${POSTAL_CODE} -${subdivision}, ${city}, ${street}, ${name} -${party_name} - - - - HR ${party_name} ${street} -${COUNTRY_CODE}-${POSTAL_CODE} ${city} +${city} +${postal_code} ${SUBDIVISION} ${COUNTRY} + ${room_number}, ${floor_number}, ${unit_number} +${building_number}, ${street_name} + Room {} + Floor {} + Building {} + No. {} + + + + CO + ${party_name} +${street} +${CITY} ${postal_code} +${COUNTRY} + ${building_name} +${street_name} ${building_number} ${unit_number} + + + + CR + ${party_name} +${street} +${subdivision} +${post_box}-${postal_code} +${COUNTRY} + ${street_name} ${building_number} +${post_office}-${post_box} + # {} + Apdo {} + + + + CU + ${party_name} +${street} +${city} +${POSTAL_CODE} ${SUBDIVISION} +${COUNTRY} + + + + CV + ${party_name} +${street} +${postal_code} ${CITY} +${SUBDIVISION} +${COUNTRY} + ${street_name} ${building_number} +${post_box} + C.P. {} + + + + CY + ${party_name} +${street} +${COUNTRY_CODE}-${postal_code} ${city} +${COUNTRY} + ${street_name} ${building_number} +${post_box} + P.O. Box {} @@ -287,24 +722,149 @@ ${COUNTRY} ${party_name} ${attn} ${street} -${COUNTRY_CODE}-${POSTAL_CODE} ${city} +${postal_code} ${CITY} ${POST_OFFICE} ${COUNTRY} + ${street_name} ${building_number} +${post_box} + poštovní přihrádka {} + + + + DE + ${party_name} +${attn} +${street} +${postal_code} ${city} +${COUNTRY} + ${street_name} ${building_number} // ${unit_number} +${post_box} + Appartement {} + Postfach {} + + + + DJ + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${post_box} + BP {} DK ${party_name} ${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number}, ${floor_number} +${post_box} + Postboks {} + + + + DM + ${party_name} +${street} +${CITY} +${COUNTRY} + ${street_name} + + + + DO + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number} +${building_name} + # {} + + + + DZ + ${party_name} +${street} ${postal_code} ${city} ${COUNTRY} + ${building_number}, ${street_name} + + + + EC + ${party_name} +${street} +${postal_code} - ${CITY} +${COUNTRY} + ${street_name} ${building_number} +${building_name}, ${floor_number} + piso {} EE ${party_name} ${street} -${postal_code} ${city} +${postal_code} ${CITY} ${COUNTRY} + ${building_name} +${street_name} ${building_number}–${unit_number} + + + + EG + ${party_name} +${street} +${city} +${subdivision} +${postal_code} +${COUNTRY} + ${building_number} ${street_name} - ${building_name} +${post_box} +${post_office} + P. O. Box {} + {} post office + + + + ER + ${party_name} +${street} +${CITY} +${COUNTRY} + ${street_name} ${building_number} + + + + ES + ${party_name} +${street} +${postal_code} ${CITY} +${SUBDIVISION} +${COUNTRY} + ${building_name} +${street_name}, ${building_number}, ${floor_number}, ${room_number} +${post_box} + Apartado {} + + + + ES + + + + + ET + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number} +${post_box} + house no {} + P.O. Box {} @@ -312,83 +872,373 @@ ${COUNTRY} ${attn} ${party_name} ${street} -${postal_code} ${city} +${postal_code} ${CITY} ${COUNTRY} + ${street_name} ${building_number} ${unit_number} + as {} + + + + FJ + ${party_name} +${STREET} +${CITY} +${COUNTRY} + ${building_number} ${street_name} + + + + FK + ${party_name} +${street} +${CITY} +${POSTAL_CODE} +${COUNTRY} + ${building_number} ${street_name} + + + + FM + + ${attn} +${party_name} +${street} +${CITY} ${SUBDIVISION_CODE} ${postal_code} +MICRONESIA (FEDERATED STATES OF) + ${building_name} +${building_number} ${street_name} ${unit_number} +${post_box} + PO Box {} FR ${party_name} ${attn} -${name} +${STREET} +${POSTAL_CODE} ${CITY} +${COUNTRY} + ${unit_number} ${floor_number} ${room_number} +${building_name} +${building_number} ${street_name} +${post_box} + BP {} + + + + GA + ${party_name} +${STREET} +${postal_code} ${CITY} ${POST_OFFICE} +${COUNTRY} + ${street_name} +${post_box} + BP {} + + + + GB + ${attn} +${party_name} ${street} +${CITY} +${POSTAL_CODE} +${COUNTRY} + ${building_name} +${building_number} ${street_name} + + + + GD + ${party_name} +${street} +${city} +${SUBDIVISION} +${COUNTRY} + ${post_box} + P.O. BOX {} + + + + GE + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number}, ${unit_number} + #{} + flat {} + + + + GF + + ${party_name} +${attn} +${STREET} +${POSTAL_CODE} ${CITY} +FRANCE + ${unit_number} ${floor_number} ${room_number} +${building_name} +${building_number} ${street_name} +${post_box} + BP {} + + + + GH + ${party_name} +${street} +${city} ${postal_code} +${SUBDIVISION} +${COUNTRY} + ${building_name} +${building_number} ${street_name} + No. {} + + + + GI + ${party_name} +${street} +${city} +${postal_code} +${COUNTRY} + ${building_name} +${building_number} ${street_name} +${post_box} + PO Box {} + + + + GM + ${party_name} +${street} +${CITY} +${COUNTRY} + ${building_number} ${street_name} + + + + GN + ${party_name} ${POSTAL_CODE} ${CITY} ${COUNTRY} - - DE + + GP + ${party_name} ${attn} -${name} -${street} -${postal_code} ${city} -${COUNTRY} +${STREET} +${POSTAL_CODE} ${CITY} +FRANCE + ${unit_number} ${floor_number} ${room_number} +${building_name} +${building_number} ${street_name} +${post_box} + BP {} GR ${party_name} -${street} +${STREET} ${COUNTRY_CODE}-${POSTAL_CODE} ${CITY} ${COUNTRY} + ${building_number}, ${street_name} +${post_box} + P.O. BOX {} + + + + GS + ${party_name} +${street} +${CITY} +${POSTAL_CODE} +SOUTH GEORGIA ISLAND + + + + GT + ${party_name} +${street} +${postal_code} - ${city} +${COUNTRY}, ${SUBDIVISION_CODE} + ${street_name} {building_number} +${unit_number} ${floor_number} ${room_number} + + + + GQ + ${attn} +${party_name} +${street} +${SUBDIVISION}, ${CITY} +${COUNTRY} + ${street_name} +${post_box} + Apartado postal {} + + + + GW + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number} + + + + HK + zh + ${COUNTRY} +${subdivision} +${street} +${party_name} + ${building_number}${building_number} +${building_name}${floor_number}${unit_number} HK ${party_name} -${name} +${room_number}, ${floor_number} ${street} -${subdivision} +${CITY} ${COUNTRY} + ${building_name} +${building_number} ${street_name} +${post_box} +${POST_OFFICE} + Flat {} + P.O. Box {} + + + + HN + ${party_name} +${street} +${POSTAL_CODE} ${CITY}, ${SUBDIVISION} +${COUNTRY} + + + + HR + ${party_name} +${street} +${COUNTRY_CODE}-${POSTAL_CODE} ${CITY} +${COUNTRY} + ${street_name} ${building_number} ${floor_number} ${room_number} +${post_box} + {} kat + stan {} + P.P. {} + + + + HT + ${party_name} +${street} +${COUNTRY_CODE}${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number} HU ${party_name} -${city} -${street} +${CITY} +${STREET} ${postal_code} ${COUNTRY} + ${street_name} ${building_number} ${unit_number} ${floor_number}/${room_number} +${post_box} + hrsz {} + fszt {} + PF. {} + + + + IE + ${party_name} +${street} +${CITY} +${POSTAL_CODE} +${COUNTRY} + ${building_name} ${building_number} ${street_name} + + + + IL + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${building_number}/${unit_number} ${street_name} + + + + IN + ${party_name} +${street} +${city} +${subdivision} +${postal_code} +${COUNTRY} + ${unit_number}, ${building_name} +${building_number}, ${street_name} IS ${party_name} ${street} -${name} -${postal_code} ${city} +${postal_code} ${CITY} ${COUNTRY} + ${street_name} ${building_number} +${post_box} + íbúð {} + Pósthólf {} - - IN - ${party_name} -${name} -${street} -${CITY} ${postal_code} -${subdivision} + + IT + ${PARTY_NAME} +${ATTN} +${STREET} +${POSTAL_CODE} ${CITY} ${SUBDIVISION_CODE} ${COUNTRY} + ${building_name} +${unit_number} ${floor_number} ${room_number} +${street_name} ${building_number} +${post_office} +${post_box} + CASELLA POSTALE {} + + IT + + + + ID ${party_name} -${name} ${street} -${city} ${postal_code} -${subdivision} +${CITY} ${postal_code} +${SUBDIVISION} ${COUNTRY} + ${building_name} ${room_number} +${street_name} ${building_number} ${unit_number} +${POST_BOX} +${POST_OFFICE} + No. {} + PO BOX {} @@ -399,53 +1249,51 @@ ${COUNTRY} IR ${party_name} -${name} ${city} ${street} ${subdivision} ${postal_code} -${COUNTRY} +IRAN (ISLAMIC REP.) + ${street_name} +${building_number}/${unit_number}/${floor_number}/${room_number} +${building_name} IQ ${party_name} ${street} -${name} -${subdivision} +${SUBDIVISION} ${postal_code} ${COUNTRY} + ${building_number} ${street_name} +${post_box} + P.O. box {} - - IE + + JM ${party_name} ${street} -${city} ${postal_code} +${city} +${subdivision} ${COUNTRY} + ${building_name} +${building_number} ${street_name} +${post_box} +${post_office} + P.O. Box {} - - IL + + JO ${party_name} ${street} -${city} ${postal_code} +${CITY} ${postal_code} ${COUNTRY} - - - - IT - ${party_name} -${attn} -${name} -${street} -${postal_code} ${city} ${SUBDIVISION_CODE} -${COUNTRY} - - - - IT - + ${building_name} +${street_name} +${building_number}–${unit_number} @@ -455,23 +1303,95 @@ ${COUNTRY} ${postal_code} ${subdivision}${city}${street} ${party_name} + ${street_name}${building_number}${building_name}${floor_number} JP ${party_name} ${street} -${city}, ${SUBDIVISION} ${postal_code} +${city}, ${SUBDIVISION} +${postal_code} ${COUNTRY} + ${floor_number}–${building_name}–${building_number}, ${street_name} + + + + KE + ${party_name} +${street} +${postal_code} +${CITY} +${COUNTRY} + ${post_box} – ${post_office} + P O BOX {} + + + + KG + ${party_name} +${street} +${postal_code} ${CITY} +${SUBDIVISION} +${COUNTRY} + ${building_number}, ${street_name}, ${unit_number} +${post_box} +${post_office} + PO-{} + + + + KH + ${party_name} +${street} +${city} +${SUBDIVISION} ${postal_code} +${COUNTRY} + ${building_number} ${street_name} + + + + KI + ${party_name} +${street} +${city} +${subdivision} ${postal_code} +${COUNTRY} + ${post_box} +${post_office} + PO Box {} + + + + KM + ${party_name} +${street} +${CITY} +${COUNTRY} + ${post_box} + BP {} + + + + KN + ${party_name} +${street} +${city} +${subdivision} +${postal_code} +ST. KITTS AND NEVIS + ${building_number} ${street_name} KR ko - ${COUNTRY} + REP. OF KOREA ${street} ${party_name} ${postal_code} + ${street_name} ${building_number}/${unit_number}/${floor_number}/${room_number} +${post_box} @@ -479,217 +1399,95 @@ ${postal_code} ${party_name} ${street} ${city}, ${subdivision} ${postal_code} -${COUNTRY} +REP. OF KOREA + ${street_name} ${building_number}/${unit_number}/${floor_number}/${room_number} +${post_box} + P.O. Box {} - - LV + + KW ${party_name} ${street} -${city} -${subdivision} -${COUNTRY_CODE}-${POSTAL_CODE} -${COUNTRY} - - - - MO - zh - ${COUNTRY} -${city} -${street} -${party_name} - - - - MO - ${party_name} -${street} -${city} -${COUNTRY} - - - - MY - ${attn} -${party_name} -${name} -${street} ${postal_code} ${CITY} -${SUBDIVISION} ${COUNTRY} + ${unit_number}, ${street_name}, ${building_number} + Parcelle {} + immeuble {} - - MX + + KY ${attn} ${party_name} ${street} -${name} -${postal_code}, ${city}, ${subdivision} +${subdivision} ${COUNTRY_CODE}${postal_code} ${COUNTRY} + ${post_box} +${post_office} + P.O. Box {} - - NL - ${party_name} -${attn} -${name} -${street} -${postal_code} ${CITY} -${COUNTRY} - - - - NZ - ${party_name} -${street} -${city} ${postal_code} -${COUNTRY} - - - - NO - ${party_name} -${street} -${postal_code} ${CITY} -${COUNTRY} - - - - OM - ${party_name} -${street} -${city} -${COUNTRY} - - - - PK - ${party_name} -${street} -${city} -${postal_code} -${subdivision} -${COUNTRY} - - - - PE - ${party_name} -${street} -${name} -${city} -${subdivision} -${COUNTRY} - - - - PH - ${party_name} -${street} -${postal_code} ${CITY} -${COUNTRY} - - - - PL - ${attn} ${party_name} -${street} -${postal_code} ${city} -${COUNTRY} - - - - PT - ${party_name} -${street} -${postal_code} ${city} -${COUNTRY} - - - - QA - ${party_name} -${street} -${city} -${COUNTRY} - - - - RO - ${attn} ${party_name} -${street} -${city} -${postal_code} -${COUNTRY} - - - - RU - ${party_name} -${street} -${city} -${subdivision} -${COUNTRY} -${postal_code} - - - - SA - ${party_name} -${street} -${city} ${postal_code} -${COUNTRY} - - - - RS - ${party_name} -${street} -${postal_code} ${city} -${COUNTRY} - - - - SG - ${party_name} -${street} -${name} -${CITY} ${POSTAL_CODE} -${COUNTRY} - - - - SK + + KZ ${attn} ${party_name} ${street} -${postal_code} ${city} +${POSTAL_CODE} ${CITY} ${COUNTRY} + ${street_name}, ${building_number}, {unit_number} +${post_box} + dom {} + kv {} + a/ya {} - - SL - ${party_name} -${attn} -${street} -${postal_code} ${city} -${COUNTRY} - - - - ES + + LA ${party_name} ${street} -${postal_code} ${city} -${subdivision} -${COUNTRY} +${postal_code} ${CITY} +LAO (PEOPLE'S DEM. REP.) + ${building_number}, ${street_name} - - ES - + + LB + ${attn} +${party_name} +${street} +${CITY} ${SUBDIVISION} +${COUNTRY} + ${building_number}, ${floor_number}, ${room_number} +${street_name} +${post_box} + P.O. Box {} + + + + LC + ${attn} +${party_name} +${street} +${SUBDIVISION}, ${POSTAL_CODE} +${COUNTRY} + ${unit_number}, ${building_number} +${street_name} +${post_box} +${post_office} + P.O Box {} + + + + LI + + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number} +${post_box} + Case postale {} @@ -699,31 +1497,1085 @@ ${street} ${CITY} ${postal_code} ${COUNTRY} + ${building_number} ${street_name} + + + + LR + ${party_name} +${street} +${postal_code} ${city} +${COUNTRY} + ${street_name} +${post_box} + P O Box {} + + + + LS + ${party_name} +${street} +${CITY} ${postal_code} +${COUNTRY} + ${post_box} + P.O. Box {} + + + + LT + ${party_name} +${street} +${city} +${COUNTRY_CODE}–${postal_code} ${SUBDIVISION} +${COUNTRY} + ${street_name} ${building_number}-${unit_number} +${post_box} +${post_office} + P. d. {} + + + + LU + ${attn} +${party_name} +${unit_number} +${street} +L-${postal_code} ${CITY} +${COUNTRY} + ${private_bag} +${building_number}, ${street_name} +${post_box} + BP {} + + + + LV + ${party_name} +${street} +${city}, ${COUNTRY_CODE}-${POSTAL_CODE} +${COUNTRY} + ${street_name} ${building_number}–${unit_number} + + + + LY + ${party_name} +${street} +${CITY} +${COUNTRY} + ${street_name} ${building_number} + + + + MA + ${PARTY_NAME} +${UNIT_NUMBER} +${STREET} +${POSTAL_CODE} ${CITY} +${COUNTRY} + ${building_name} +${building_number} ${street_name} +${post_box} +${post_office} + APARTMENT N° {} + P.O {} + + + + MC + + ${party_name} +${attn} +${STREET} +${POSTAL_CODE} ${CITY} +${COUNTRY} + ${unit_number} ${floor_number} ${room_number} +${building_name} +${building_number} ${street_name} +${post_box} + BP {} + + + + MD + ${party_name} +${street} +${POSTAL_CODE}, ${CITY} +MOLDOVA + ${street_name}, ${building_number}, ${unit_number} +${post_box} +${post_office} + nr. {} + ap. {} + Căsuţa poştăla {} + + + + ME + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number} / ${unit_number} +${post_box} +${post_office} + PP {} + + + + MG + ${attn} +${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${unit_number} ${building_number} ${building_name} +${post_box} + B.P. {} + + + + MH + + ${attn} +${party_name} +${street} +${CITY} ${SUBDIVISION_CODE} ${postal_code} +${COUNTRY} + ${building_name} +${building_number} ${street_name} ${unit_number} +${post_box} + PO Box {} + + + + MK + ${party_name} +${street} +${postal_code} ${city} +${COUNTRY} + ${street_name} ${building_number} +${post_box} + P. fah {} + + + + ML + ${attn} +${party_name} +${street} +${CITY} +${COUNTRY} + ${street_name} – ${building_number} + Porte {} + + + + MM + ${attn} +${party_name} +${street} +${CITY} ${POST_OFFICE}, ${postal_code} +${subdivision} +${COUNTRY} + ${building_number}, ${street_name} +${post_box} + No. {} + P.O Box ({}) + + + + MN + ${party_name} +${street} +${city} +${SUBDIVISION} ${postal_code} +${COUNTRY} + ${street_name} ${building_number} +${post_box} ${post_office} + PO.Box {} + PO {} + + + + MO + zh + ${COUNTRY} +${city} +${street} +${party_name} + ${street_name} ${building_number} +${building_name}${floor_number}${room_number} +${post_box} +${post_office} + P.O. Box {} + + + + MO + ${party_name} +${street} +${city} +${COUNTRY} + ${street_name}, ${building_number}, ${building_name}, ${floor_number}, ${room_number} +${post_box} +${post_office} + n.o {} + {} andar + moradia {} + P.O. Box {} + + + + MQ + + ${party_name} +${attn} +${STREET} +${POSTAL_CODE} ${CITY} +${COUNTRY} + ${unit_number} ${floor_number} ${room_number} +${building_name} +${building_number} ${street_name} +${post_box} + BP {} + + + + MR + ${party_name} +${street} +${CITY} +${COUNTRY} + ${post_box} + B.P. {} + + + + MS + ${party_name} +${street} +${city}, ${POSTAL_CODE} +${COUNTRY} + ${street_name} +${post_box} + PO Box {} + + + + MT + ${party_name} +${street} +${CITY} +${POSTAL_CODE} +${COUNTRY} + ${building_number} ${street_name} +${post_box} + Kaxxa Postali {} + + + + MU + ${attn} +${party_name} +${street} +${city} ${postal_code} +${COUNTRY} + ${building_number}, ${street_name} + + + + MV + ${party_name} +${STREET} +${CITY} ${postal_code} +${COUNTRY} + ${building_number}, ${street_name} + + + + MW + ${attn} +${party_name} +${street} +${city} +${postal_code} ${SUBDIVISION} +${COUNTRY} + ${building_name} +${building_number} ${street_name} +${post_box} + P. O. Box {} + + + + MX + ${attn} +${party_name} +${street} +${postal_code} ${CITY}, ${SUBDIVISION_CODE} +${COUNTRY} + ${street_name} ${building_number} ${unit_number} ${floor_number} ${room_number} +${building_name} + + + + MY + ${attn} +${party_name} +${street} +${postal_code} ${CITY} +${SUBDIVISION} +${COUNTRY} + ${unit_number}, ${floor_number}, ${room_number}, ${building_name} +${building_number}, ${street_name} +${post_box} + Peti surat {} + + + + MZ + ${party_name} +${street} +${postal_code} ${CITY} +${SUBDIVISION} +${COUNTRY} + ${street_name} +${building_number}, ${floor_number}, ${room_number} +${post_box} + P.O Box {} + + + + NA + ${attn} +${party_name} +${street} +${CITY} +${postal_code} +${COUNTRY} + ${building_name} +${building_number}/${unit_number} ${street_name} +${post_box} +${POST_OFFICE} + PO Box {} + + + + NC + ${party_name} +${unit_number} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${building_name} +${building_number} ${street_name} +${post_box} + APPARTEMENT {} + BP {} + + + + NE + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${post_box} + BP {} + + + + NF + + ${party_name} +${attn} +${street} +${CITY} ${SUBDIVISION_CODE} ${POSTAL_CODE} +${COUNTRY} + ${building_name} +${room_number}/${floor_number}/${unit_number}/${building_number} ${street_name} +${post_box} + PO BOX {} + + + + NG + ${attn} +${party_name} +${street} +${city} ${postal_code} +${SUBDIVISION} +${COUNTRY} + ${building_number} ${street_name} +${post_box} + P.O.Box. {} + + + + NI + ${party_name} +${street} +${postal_code} +${city}, ${subdivision} +${COUNTRY} + ${street_name}, ${building_number} + + + + NL + ${party_name} +${attn} +${street} +${POSTAL_CODE} ${CITY} +${COUNTRY} + ${building_name} +${street_name} ${building_number} +${post_box} + Postbus {} + + + + NO + ${party_name} +${attn} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${building_name} +${street_name} ${building_number} +${post_box} ${post_office} + Postboks {} + + + + NP + ${party_name} +${street} +${CITY} ${postal_code} +${COUNTRY} + ${building_number}, ${street_name} +${building_name} + + + + NR + ${party_name} +${STREET} +${SUBDIVISION} +${POSTAL_CODE} +${COUNTRY} + ${building_name} + + + + NZ + ${attn} +${party_name} +${street} +${CITY} ${postal_code} +${COUNTRY} + ${unit_number}/${building_number} ${street_name} +${building_name} + PO Box {} + + + + OM + ${party_name} +${street} +${postal_code} +${CITY} +${COUNTRY} + ${building_number} ${street_name} + BP {} + + + + PA + ${ATTN} +${PARTY_NAME} +${STREET} +${CITY} +${SUBDIVISION} +${COUNTRY} + ${street_name} ${building_number} +${building_name} +${post_box} +${post_office} +${private_bag} + APARTADO POSTAL {} + Private Bag {} + + + + PE + ${party_name} +${street}, ${city} +${postal_code} +${SUBDIVISION} +${COUNTRY} + ${street_name} ${building_number} + + + + PF + + ${party_name} +${attn} +${STREET} +${POSTAL_CODE} ${CITY} ${SUBDIVISION} +${COUNTRY} + ${unit_number} ${floor_number} ${room_number} +${building_name} +${building_number} ${street_name} +${post_box} + BP {} + + + + PG + ${party_name} +${street} +${CITY} ${POSTAL_CODE} +${COUNTRY} + ${post_box} + P.O. Box {} + + + + PH + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${building_number} ${street_name} +${post_box}, ${post_office} + P.O. Box {} + + + + PK + ${party_name} +${street} +${CITY}–${postal_code} +${COUNTRY} + ${building_number} +${street_name} +${unit_number} + House No {} + Sector {} + + + + PL + ${attn} ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number}/${unit_number} +${post_box} + Skrytka pocztowa {} + + + + PM + + ${party_name} +${attn} +${STREET} +${POSTAL_CODE} ${CITY} +FRANCE + ${unit_number} ${floor_number} ${room_number} +${building_name} +${building_number} ${street_name} +${post_box} + BP {} + + + + PN + ${attn} +${party_name} +${street} +${CITY} +${POSTAL_CODE} +${COUNTRY} + ${building_name} +${building_number} ${street_name} + + + + PT + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number} ${unit_number} +${building_name} +${post_box} +${post_office} + APARTADO {} + + + + PW + + ${attn} +${party_name} +${street} +${CITY} ${SUBDIVISION_CODE} ${postal_code} +${COUNTRY} + ${building_name} +${building_number} ${street_name} ${unit_number} +${post_box} + PO Box {} + + + + PY + ${party_name} +${street} +${floor_number}, ${room_number} +${postal_code} ${CITY}, ${SUBDIVISION} +${COUNTRY} + ${street_name} ${building_number} +${building_name} + Nº {} + Piso {} + Depto. {} + + + + QA + ${party_name} +${attn} +${street} +${CITY} +${COUNTRY} + ${unit_number}, ${street_name} ${building_number} +${post_box} + P.O. Box {} + + + + RE + + ${party_name} +${attn} +${STREET} +${POSTAL_CODE} ${CITY} +FRANCE + ${unit_number} ${floor_number} ${room_number} +${building_name} +${building_number} ${street_name} +${post_box} + BP {} + + + + RO + ${attn} ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name}, ${building_number}, ${unit_number}, ${floor_number}, ${room_number} +${building_name} + nr. {} + bl. {} + sc. {} + ap. {} + + + + RU + ${party_name} +${street} +${city} +${SUBDIVISION} +${COUNTRY} +${postal_code} + ${street_name}, ${building_number}, ${unit_number}, ${room_number} + d. {} + kv. {} + kv. {} + + + + RS + ${party_name} +${street} +${CITY} +${UNIT_NUMBER} +${POSTAL_CODE} +${COUNTRY} + ${street_name} ${building_number}/${room_number} +${post_box} + PP {} + + + + RW + ${party_name} +${street} +${CITY} +${COUNTRY} + ${post_box} + B.P. {} + + + + SA + ${party_name} +${street} +${postal_code} +${CITY} +${COUNTRY} + ${building_number} ${street_name} +${post_box} + P.O. Box {} + + + + SB + ${party_name} +${street} +${CITY} +${COUNTRY} + ${post_box} + P.O. Box {} + + + + SC + ${party_name} +${street} +${unit_number} +${city} +${SUBDIVISION} +${COUNTRY} + ${post_box} +${building_name} +${building_number} +${street_name} + P.O.Box {} + + + + SD + ${party_name} +${street} +${postal_code} +${CITY} +${COUNTRY} + ${building_name} +${street_name} +${unit_number} + B.P. {} SE + ${PARTY_NAME} +${STREET} +${POSTAL_CODE} ${CITY} +${COUNTRY} + ${street_name} ${building_number} +${post_box} + BOX {} + + + + SG + ${party_name} +${street} +${CITY} ${POSTAL_CODE} +${COUNTRY} + ${building_number} ${unit_number} ${street_name} +${floor_number}–${room_number} ${building_name} + # {} + + + + SH + ${party_name} +${street} +${CITY} +${POSTAL_CODE} +SOUTH ATLANTIC OCEAN +VIA CAPE TOWN, SOUTH AFRICA + ${building_number} ${street_name} + + + + SI + ${attn} +${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number} +${post_box} + p.p. {} + + + + SK + ${attn} +${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number} +${building_name} +${post_box} + P.O. Box {} + + + + SL + ${party_name} +${street} +${CITY} +${COUNTRY} + ${street_name} ${building_number} + + + + SM + + ${PARTY_NAME} +${ATTN} +${STREET} +${POSTAL_CODE} ${CITY} ${SUBDIVISION_CODE} +${COUNTRY} + ${building_name} +${unit_number} ${floor_number} ${room_number} +${street_name} ${building_number} +${post_office} +${post_box} + CASELLA POSTALE {} + + + + SN + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${room_number} +${building_name} +${building_number} ${street_name} +${unit_number} +${post_box} + Appartement {} + BP {} + BP {} + + + + SO + ${party_name} +${street} +${CITY}, ${POSTAL_CODE} +${COUNTRY} + ${post_box} + P.O. Box {} + + + + SR + ${party_name} +${street} +${city} +${SUBDIVISION} +${COUNTRY} + ${street_name} ${building_number} + + + + ST ${party_name} ${street} -${postal_code} ${city} ${COUNTRY} - - CH + + SV + ${party_name} +${STREET} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number} +${building_name} +${post_box} +${post_office} + APARTADO POSTAL {} + + + + SZ ${party_name} ${street} -${postal_code} ${city} +${CITY} +${postal_code} ${COUNTRY} + ${post_box} + P.O. Box {} + + + + SY + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${floor_number} ${room_number} +${street_name} ${building_number} +${unit_number} + + + + TC + + ${attn} +${party_name} +${street} +${CITY} +${POSTAL_CODE} +${COUNTRY} + ${building_name} +${building_number} ${street_name} + + + + TD + ${party_name} +${street} +${CITY} +${COUNTRY} + ${post_box} + BP {} + + + + TG + ${party_name} +${street} +${CITY} +${COUNTRY} + ${post_box} + B.P. {} + + + + TH + ${party_name} +${street} +${subdivision} +${postal_code} +${COUNTRY} + ${building_name} +${building_number}/${unit_number} ${street_name} +${post_box} +${post_office} + PO Box {} + + + + TJ + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${street_name} ${building_number} street + + + + TL + ${party_name} +${STREET} +${CITY} ${POSTAL_CODE} +${post_box} +${COUNTRY} + ${building_name} +${street_name} ${building_number} + PO Box {} + + + + TM + ${party_name} +${street} +${city} +${SUBDIVISION} +${postal_code} +${COUNTRY} + ${street_name} ${building_number} ${unit_number} +${building_name} +${post_box} + otag {} + m/g {} + + + + TN + ${party_name} +${street} +${postal_code} ${CITY} +${COUNTRY} + ${building_number} ${street_name} +${post_box} + BOITE PRIVEE {} + + + + TR + ${attn} +${party_name} +${street} +${postal_code} ${CITY}/${SUBDIVISION} +${COUNTRY} + ${street_name} ${building_number} +${building_name} + + + + TT + ${attn} +${party_name} +${street} +${CITY} ${postal_code} +${COUNTRY} + ${building_number} ${street_name} +${post_box} +${private_bag} + PO Box {} + PO BAG {} + + + + TV + ${attn} +${party_name} +${street} +${POSTAL_CODE} ${city} +${SUBDIVISION} +${COUNTRY} + ${street_name} ${building_number} +${post_box} + P.O.Box {} TW zh - ${COUNTRY} + Taiwan (R.O.C.) ${postal_code} ${street} ${party_name} + ${street_name} +${building_number} +${floor_number} @@ -731,46 +2583,48 @@ ${party_name} ${party_name} ${street} ${city}, ${subdivision} ${postal_code} -${COUNTRY} +Taiwan (R.O.C.) + ${floor_number}, ${building_number}, ${street_name} - - TH - ${party_name} + + TZ + ${attn} +${party_name} ${street} -${name} -${subdivision} -${COUNTRY} -${postal_code} - - - - TR - ${party_name} -${attn} -${street} -${name} -${postal_code} ${city} ${subdivision} -${COUNTRY} +${postal_code} ${CITY} +${SUBDIVISION} +TANZANIA + ${unit_number} +${building_number} ${street_name} +${post_box} +${private_bag} + P.O. Box {} + Private Bag {} UA - ${party_name} + ${attn} +${party_name} ${street} -${city} -${subdivision} +${CITY} +${SUBDIVISION} ${postal_code} ${COUNTRY} + ${street_name}, ${building_number}, ${unit_number}, ${room_number} + d. {} + kv. {} - - GB + + UG ${party_name} ${street} ${CITY} -${postal_code} ${COUNTRY} + ${post_box} + P.O. Box {} @@ -778,17 +2632,202 @@ ${COUNTRY} ${attn} ${party_name} ${street} -${city}, ${subdivision_code} ${postal_code} +${CITY} ${SUBDIVISION_CODE} ${postal_code} ${COUNTRY} + ${building_name} +${building_number} ${street_name} ${unit_number} +${post_box} + PO Box {} + + + + UY + ${party_name} +${attn} +${street} +${postal_code} – ${CITY}, ${SUBDIVISION} +${COUNTRY} + ${street_name} ${building_number} ${unit_number} ${floor_number} ${room_number} +${building_name} + + + + UZ + ${attn} +${party_name} +${street} +${postal_code}, ${city} +${COUNTRY} + ${street_name}, ${building_number}, ${unit_number} +${building_name} +${post_box} +${post_office} + d. {} + kv. {} + a/ya. {} + + + + VC + ${PARTY_NAME} +${STREET} +${CITY} +${POSTAL_CODE} +${COUNTRY} + ${street_name} +${post_box} + P.O BOX {} + + + + VA + + ${PARTY_NAME} +${ATTN} +${STREET} +${POSTAL_CODE} ${CITY} +VATICAN + ${building_name} +${unit_number} ${floor_number} ${room_number} +${street_name} ${building_number} +${post_office} +${post_box} + CASELLA POSTALE {} + + + + VE + ${PARTY_NAME} +${STREET} +${CITY} ${postal_code}, ${SUBDIVISION} +VENEZUELA + ${street_name} +${building_number} +${floor_number}, ${room_number} +${building_name} +${post_box} + PISO {} + APARTAMENTO {} + APARTADO POSTAL Nº {} + + + + VG + ${party_name} +${street} +${CITY} ${POSTAL_CODE} +BRITISH VIRGIN ISLANDS + ${post_box} +${building_number} ${street_name} + #{} + P.O. Box {} VN ${party_name} +${unit_number} ${street} ${city} -${subdivision} +${SUBDIVISION} ${postal_code} ${COUNTRY} + ${building_number} ${street_name} +${building_name} + GPO {} + + + + WF + + ${party_name} +${attn} +${STREET} +${POSTAL_CODE} ${CITY} +FRANCE + ${unit_number} ${floor_number} ${room_number} +${building_name} +${building_number} ${street_name} +${post_box} + BP {} + + + + WS + ${party_name} +${street} +${city} ${POSTAL_CODE} +${COUNTRY} + ${post_box} + PO Box {} + + + + YE + ${party_name} +${street} +${SUBDIVISION} +${COUNTRY} + ${post_box} + B.P. {} + + + + YT + + ${party_name} +${attn} +${STREET} +${POSTAL_CODE} ${CITY} +FRANCE + ${unit_number} ${floor_number} ${room_number} +${building_name} +${building_number} ${street_name} +${post_box} + BP {} + + + + ZA + ${attn} +${party_name} +${street} +${CITY} +${postal_code} +${COUNTRY} + ${unit_number} ${building_name} +${building_number} ${street_name} +${post_box} +${private_bag} +${post_office} + PO Box {} + Private Bag {} + + + + ZM + ${attn} +${party_name} +${street} +${CITY} ${postal_code} +${COUNTRY} + ${building_name} +${building_number} ${street_name} +${post_box} +${private_bag} + P.O. Box {} + Private Bag {} + + + + ZW + ${party_name} +${street} +${city} +${SUBDIVISION} +${COUNTRY} + ${building_number}–${unit_number} ${street_name} +${post_box} + P.O. Box {} diff --git a/modules/party/party.py b/modules/party/party.py index 5f09c076a6..0b40ffdeff 100644 --- a/modules/party/party.py +++ b/modules/party/party.py @@ -1194,9 +1194,11 @@ class Erase(Wizard): ['type', 'code'], [None, '****']), (Address, [('party', '=', party_id)], True, - ['name', 'street', 'postal_code', 'city', - 'country', 'subdivision'], - [None, None, None, None, None, None]), + ['street_unstructured', 'street_name', 'building_name', + 'building_number', 'unit_number', 'floor_number', + 'room_number', 'post_box', 'private_bag', 'post_office', + 'postal_code', 'city', 'country', 'subdivision'], + [None] * 14), (ContactMechanism, [('party', '=', party_id)], True, ['value', 'name', 'comment'], [None, None, None]), diff --git a/modules/party/tests/test_module.py b/modules/party/tests/test_module.py index e2287c4316..b3d7e3df1f 100644 --- a/modules/party/tests/test_module.py +++ b/modules/party/tests/test_module.py @@ -200,6 +200,31 @@ class PartyTestCase(PartyCheckEraseMixin, ModuleTestCase): }], }) + @with_transaction() + def test_address_strip(self): + "Test address strip" + pool = Pool() + Address = pool.get('party.address') + for value, result in [ + ('', ''), + (' ', ''), + ('\n', ''), + (' \n \n', ''), + ('foo\n\n', 'foo'), + (',foo', 'foo'), + (',,foo', 'foo'), + (', , foo', 'foo'), + ('foo, , bar', 'foo, bar'), + ('foo,,', 'foo'), + ('foo, , ', 'foo'), + (',/–foo,/–', 'foo'), + ('foo, /bar', 'foo/bar'), + ('foo, /, bar', 'foo, bar'), + ('foo,/bar\nfoo, –\n/bar, foo', 'foo/bar\nfoo\nbar, foo'), + ]: + with self.subTest(value=value): + self.assertEqual(Address._strip(value), result) + @with_transaction() def test_address(self): 'Create address' @@ -226,6 +251,35 @@ class PartyTestCase(PartyCheckEraseMixin, ModuleTestCase): "St sample, 15\n" "City") + @with_transaction() + def test_address_structured(self): + "Test address structured" + pool = Pool() + Address = pool.get('party.address') + Country = pool.get('country.country') + + us = Country(code='US', name="US") + us.save() + be = Country(code='BE', name="BE") + be.save() + + address = Address( + street_name="St sample", + building_number="15", + unit_number="B", + floor_number=1, + room_number=3, + ) + + for country, result in [ + (None, "St sample 15/B/1/3"), + (us, "15 St sample B"), + (be, "St sample 15 box B"), + ]: + with self.subTest(country=country.code if country else None): + address.country = country + self.assertEqual(address.street, result) + @with_transaction() def test_address_autocomplete_postal_code(self): "Test autocomplete of postal code" diff --git a/modules/party/view/address_form.xml b/modules/party/view/address_form.xml index be22c9f673..902c52e29f 100644 --- a/modules/party/view/address_form.xml +++ b/modules/party/view/address_form.xml @@ -16,12 +16,35 @@ this repository contains the full copyright notices and license terms. --> -