diff --git a/CHANGELOG b/CHANGELOG index ca0a0b0d60..9eed3a2ae3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Add UN M49 regions * Add flag symbol for country and subdivision Version 6.4.0 - 2022-05-02 diff --git a/__init__.py b/__init__.py index 80dff9d0ce..b229037c5f 100644 --- a/__init__.py +++ b/__init__.py @@ -8,6 +8,7 @@ def register(): # Prevent to import backend when importing scripts from . import country Pool.register( + country.Region, country.Country, country.Subdivision, country.PostalCode, diff --git a/country.py b/country.py index a83cc8efc6..a53df52a01 100644 --- a/country.py +++ b/country.py @@ -1,13 +1,49 @@ # 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 import backend -from trytond.model import DeactivableMixin, ModelSQL, ModelView, fields +from trytond.model import DeactivableMixin, ModelSQL, ModelView, fields, tree from trytond.pool import Pool from trytond.pyson import Eval from trytond.tools import lstrip_wildcard from trytond.transaction import Transaction +class Region(tree(), ModelSQL, ModelView): + "Region" + __name__ = 'country.region' + + name = fields.Char("Name", required=True, translate=True) + code_numeric = fields.Char( + "Numeric Code", size=3, + help="UN M49 region code.") + parent = fields.Many2One('country.region', "Parent") + subregions = fields.One2Many('country.region', 'parent', "Subregions") + countries = fields.One2Many( + 'country.country', 'region', "Countries", + add_remove=[ + ('region', '=', None), + ]) + + @classmethod + def __setup__(cls): + super().__setup__() + cls._order.insert(0, ('name', 'ASC')) + + @classmethod + def search_rec_name(cls, name, clause): + if clause[1].startswith('!') or clause[1].startswith('not '): + bool_op = 'AND' + else: + bool_op = 'OR' + code_value = clause[2] + if clause[1].endswith('like'): + code_value = lstrip_wildcard(clause[2]) + return [bool_op, + ('name',) + tuple(clause[1:]), + ('code_numeric', clause[1], code_value) + tuple(clause[3:]), + ] + + class Country(DeactivableMixin, ModelSQL, ModelView): 'Country' __name__ = 'country.country' @@ -20,6 +56,8 @@ class Country(DeactivableMixin, ModelSQL, ModelView): code_numeric = fields.Char('Numeric Code', select=True, help="The ISO numeric country code.") flag = fields.Function(fields.Char("Flag"), 'on_change_with_flag') + region = fields.Many2One( + 'country.region', "Region", ondelete='SET NULL') subdivisions = fields.One2Many('country.subdivision', 'country', 'Subdivisions') diff --git a/country.xml b/country.xml index 55d22192f7..f848c2ebde 100644 --- a/country.xml +++ b/country.xml @@ -8,6 +8,96 @@ this repository contains the full copyright notices and license terms. --> icons/tryton-country.svg + + + + + + + + country.region + form + region_form + + + + country.region + tree + + region_list + + + + country.region + tree + + subregions + region_tree + + + + Areas + country.region + + + + + + + + + + + + + + + + Regions + country.region + + + + + + + + + + + + + + + + + + + + + + + + + + + + + country.country form @@ -33,15 +123,23 @@ this repository contains the full copyright notices and license terms. --> - - - + sequence="10" + id="menu_country_form"/> + + + Countries by Region + country.country + + + + tree_open + country.region,-1 + diff --git a/doc/design.rst b/doc/design.rst index c2e93901de..148448d74f 100644 --- a/doc/design.rst +++ b/doc/design.rst @@ -4,6 +4,26 @@ Design The *Country Module* introduces the following concepts: +.. _model-country.region: + +Region +====== + +The *Region* represents a geographical region that groups `Countries `. +The main usage is for reporting and statistics. + +The `UN M49 `_ methodology and +codes are used when `Loading and updating countries and subdivisions`. + +.. seealso:: + + Regions can be found under the main menu entry: + + |Administration --> Countries --> Regions|__ + + .. |Administration --> Countries --> Regions| replace:: :menuselection:`Administration --> Countries --> Regions` + __ https://demo.tryton.org/model/country.region + .. _model-country.country: Country @@ -20,9 +40,9 @@ The ISO 3166 standard defines the codes and names of countries and is used when Countries can be found under the main menu entry: - |Administration --> Countries|__ + |Administration --> Countries --> Countries|__ - .. |Administration --> Countries| replace:: :menuselection:`Administration --> Countries` + .. |Administration --> Countries --> Countries| replace:: :menuselection:`Administration --> Countries` __ https://demo.tryton.org/model/country.country .. _model-country.subdivision: diff --git a/region.xml b/region.xml new file mode 100644 index 0000000000..8f4f837a8c --- /dev/null +++ b/region.xml @@ -0,0 +1,206 @@ + + + + + + World + 001 + + + + + Africa + 002 + + + + + Antarctica + 010 + + + + + Americas + 019 + + + + + Asia + 142 + + + + + Europe + 150 + + + + + Oceania + 009 + + + + + + Northern Africa + 015 + + + + + Sub-Saharan Africa + 202 + + + + + North America + 003 + + + + + Latin America and the Caribbean + 419 + + + + + Eastern Asia + 030 + + + + + Southern Asia + 034 + + + + + South-eastern Asia + 035 + + + + + Central Asia + 143 + + + + + Western Asia + 145 + + + + + Southern Europe + 039 + + + + + Eastern Europe + 151 + + + + + Northern Europe + 154 + + + + + Western Europe + 155 + + + + + Australia and New Zealand + 053 + + + + + Melanesia + 054 + + + + + Micronesia + 057 + + + + + Polynesia + 061 + + + + + + Western Africa + 011 + + + + + Eastern Africa + 014 + + + + + Middle Africa + 017 + + + + + Southern Africa + 018 + + + + + Northern America + 021 + + + + + South America + 005 + + + + + Central America + 013 + + + + + Caribbean + 029 + + + + + Channel Islands + 830 + + + + diff --git a/scripts/import_countries.py b/scripts/import_countries.py index c8f07c7384..6d33eac824 100755 --- a/scripts/import_countries.py +++ b/scripts/import_countries.py @@ -25,6 +25,63 @@ except ImportError: prog = os.path.basename(sys.argv[0]) sys.exit("proteus must be installed to use %s" % prog) +SUBREGIONS = { + '001': ['002', '009', '010', '019', '142', '150'], + '002': ['015', '202'], + '015': ['012', '434', '504', '729', '732', '788', '818'], + '202': ['011', '014', '017', '018'], + '011': [ + '132', '204', '270', '288', '324', '384', '430', '466', '478', '562', + '566', '624', '654', '686', '694', '768', '854'], + '014': [ + '086', '108', '174', '175', '231', '232', '260', '262', '404', '450', + '454', '480', '508', '638', '646', '690', '706', '716', '728', '800', + '834', '894'], + '017': ['024', '120', '140', '148', '178', '180', '226', '266', '678'], + '018': ['072', '426', '516', '710', '748'], + '010': [], + '019': ['003', '419'], + '003': ['013', '021', '029'], + '021': ['060', '124', '304', '666', '840'], + '419': ['005', '013', '029'], + '005': [ + '032', '068', '074', '076', '152', '170', '218', '238', '239', '254', + '328', '600', '604', '740', '858', '862'], + '013': ['084', '188', '222', '320', '340', '484', '558', '591'], + '029': [ + '028', '044', '052', '092', '136', '192', '212', '214', '308', '312', + '332', '388', '474', '500', '531', '533', '534', '535', '630', '652', + '659', '660', '662', '663', '670', '780', '796', '850'], + '142': ['030', '034', '035', '143', '145'], + '030': ['156', '344', '392', '408', '410', '446', '496'] + ['158'], + '034': ['004', '050', '064', '144', '356', '364', '462', ' 524', '586'], + '035': [ + '096', '104', '116', '360', '418', '458', '608', '626', '702', '704', + '764'], + '143': ['398', '417', '762', '795', '860'], + '145': [ + '031', '051', '048', '196', '268', '275', '368', '376', '400', '414', + '422', '512', '634', '682', '760', '792', '784', '887'], + '150': ['039', '151', '154', '155'], + '039': [ + '008', '020', '070', '191', '292', '300', '336', '380', '470', '499', + '620', '674', '688', '705', '724', '807'], + '151': [ + '100', '112', '203', '348', '498', '616', '642', '643', '703', '804'], + '154': [ + '208', '233', '234', '246', '248', '352', '372', '428', '440', '578', + '744', '752', '826', '833', '830'], + '830': ['831', '832', '680'], + '155': ['040', '056', '250', '276', '438', '442', '492', '528', '756'], + '009': ['053', '054', '057', '061'], + '053': ['036', '162', '166', '334', '554', '574'], + '054': ['090', '242', '540', '548', '598'], + '057': ['296', '316', '520', '580', '581', '583', '584', '585'], + '061': [ + '016', '184', '258', '570', '612', '772', '776', '798', '876', '882'], + } +REGION2PARENT = {c: p for p, r in SUBREGIONS.items() for c in r} + def _progress(iterable): if ProgressBar: @@ -54,8 +111,11 @@ def get_countries(): def update_countries(countries): print("Update countries", file=sys.stderr) + Region = Model.get('country.region') Country = Model.get('country.country') + code2region = {a.code_numeric: a for a in Region.find([])} + records = [] for country in _progress(pycountry.countries): code = country.alpha_2 @@ -66,6 +126,7 @@ def update_countries(countries): record.name = _remove_forbidden_chars(country.name) record.code3 = country.alpha_3 record.code_numeric = country.numeric + record.region = code2region.get(REGION2PARENT.get(country.numeric)) records.append(record) Country.save(records) diff --git a/tryton.cfg b/tryton.cfg index 4687a5a9c4..65b4cf72da 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -5,3 +5,4 @@ depends: res xml: country.xml + region.xml diff --git a/view/country_form.xml b/view/country_form.xml index f62457bd67..7042e8479b 100644 --- a/view/country_form.xml +++ b/view/country_form.xml @@ -4,9 +4,11 @@ this repository contains the full copyright notices and license terms. -->