first commit
This commit is contained in:
2
modules/country/__init__.py
Normal file
2
modules/country/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
BIN
modules/country/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
modules/country/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
modules/country/__pycache__/country.cpython-311.pyc
Normal file
BIN
modules/country/__pycache__/country.cpython-311.pyc
Normal file
Binary file not shown.
500
modules/country/country.py
Normal file
500
modules/country/country.py
Normal file
@@ -0,0 +1,500 @@
|
||||
# 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 datetime as dt
|
||||
import operator
|
||||
|
||||
from sql import Literal
|
||||
from sql.conditionals import Coalesce
|
||||
from sql.functions import Position, Substring
|
||||
|
||||
from trytond.model import DeactivableMixin, ModelSQL, ModelView, fields, tree
|
||||
from trytond.pool import Pool
|
||||
from trytond.pyson import Eval, If
|
||||
from trytond.tools import is_full_text, lstrip_wildcard
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
|
||||
class Organization(ModelSQL, ModelView):
|
||||
__name__ = 'country.organization'
|
||||
|
||||
name = fields.Char("Name", required=True, translate=True)
|
||||
code = fields.Char("Code")
|
||||
members = fields.One2Many(
|
||||
'country.organization.member', 'organization', "Members",
|
||||
filter=[
|
||||
('active', 'in', [True, False]),
|
||||
])
|
||||
countries = fields.Many2Many(
|
||||
'country.organization.member', 'organization', 'country', "Countries",
|
||||
readonly=True)
|
||||
|
||||
|
||||
class OrganizationMember(ModelSQL, ModelView):
|
||||
__name__ = 'country.organization.member'
|
||||
|
||||
organization = fields.Many2One(
|
||||
'country.organization', "Organization", required=True)
|
||||
country = fields.Many2One(
|
||||
'country.country', "Country", required=True)
|
||||
from_date = fields.Date(
|
||||
"From Date",
|
||||
domain=[
|
||||
If(Eval('from_date') & Eval('to_date'),
|
||||
('from_date', '<=', Eval('to_date')),
|
||||
()),
|
||||
])
|
||||
to_date = fields.Date(
|
||||
"To Date",
|
||||
domain=[
|
||||
If(Eval('from_date') & Eval('to_date'),
|
||||
('to_date', '>=', Eval('from_date')),
|
||||
()),
|
||||
])
|
||||
active = fields.Function(fields.Boolean("Active"), 'on_change_with_active')
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls._order.insert(0, ('country', None))
|
||||
cls._order.insert(1, ('from_date', 'ASC NULLS FIRST'))
|
||||
cls.__access__.add('organization')
|
||||
|
||||
@classmethod
|
||||
def default_active(cls):
|
||||
return True
|
||||
|
||||
@fields.depends('from_date', 'to_date')
|
||||
def on_change_with_active(self, name=None):
|
||||
pool = Pool()
|
||||
Date = pool.get('ir.date')
|
||||
context = Transaction().context
|
||||
date = context.get('date', Date.today())
|
||||
|
||||
from_date = self.from_date or dt.date.min
|
||||
to_date = self.to_date or dt.date.max
|
||||
return from_date <= date <= to_date
|
||||
|
||||
@classmethod
|
||||
def domain_active(cls, domain, tables):
|
||||
pool = Pool()
|
||||
Date = pool.get('ir.date')
|
||||
context = Transaction().context
|
||||
table, _ = tables[None]
|
||||
_, operator, operand = domain
|
||||
date = context.get('date', Date.today())
|
||||
|
||||
from_date = Coalesce(table.from_date, dt.date.min)
|
||||
to_date = Coalesce(table.to_date, dt.date.max)
|
||||
|
||||
expression = (from_date <= date) & (to_date >= date)
|
||||
|
||||
if operator in {'=', '!='}:
|
||||
if (operator == '=') != operand:
|
||||
expression = ~expression
|
||||
elif operator in {'in', 'not in'}:
|
||||
if True in operand and False not in operand:
|
||||
pass
|
||||
elif False in operand and True not in operand:
|
||||
expression = ~expression
|
||||
else:
|
||||
expression = Literal(True)
|
||||
else:
|
||||
expression = Literal(True)
|
||||
return expression
|
||||
|
||||
|
||||
class Region(tree(), ModelSQL, ModelView):
|
||||
__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):
|
||||
__name__ = 'country.country'
|
||||
name = fields.Char(
|
||||
"Name", required=True, translate=True,
|
||||
help="The main identifier of the country.")
|
||||
code = fields.Char(
|
||||
"Code", size=2,
|
||||
help="The 2 chars ISO country code.")
|
||||
code3 = fields.Char(
|
||||
"3-letters Code", size=3,
|
||||
help="The 3 chars ISO country code.")
|
||||
code_numeric = fields.Char(
|
||||
"Numeric Code",
|
||||
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')
|
||||
members = fields.One2Many(
|
||||
'country.organization.member', 'country', "Members",
|
||||
filter=[
|
||||
('active', 'in', [True, False]),
|
||||
])
|
||||
organizations = fields.Many2Many(
|
||||
'country.organization.member', 'country', 'organization',
|
||||
"Organizations", readonly=True)
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls._order.insert(0, ('name', 'ASC'))
|
||||
|
||||
@fields.depends('code')
|
||||
def on_change_with_flag(self, name=None):
|
||||
if self.code:
|
||||
return ''.join(map(chr, map(lambda c: 127397 + ord(c), self.code)))
|
||||
|
||||
def get_rec_name(self, name):
|
||||
name = self.name
|
||||
if self.flag:
|
||||
name = ' '.join([self.flag, self.name])
|
||||
return name
|
||||
|
||||
@classmethod
|
||||
def search_rec_name(cls, name, clause):
|
||||
_, operator, operand, *extra = clause
|
||||
if operator.startswith('!') or operator.startswith('not '):
|
||||
bool_op = 'AND'
|
||||
else:
|
||||
bool_op = 'OR'
|
||||
code_value = operand
|
||||
if operator.endswith('like') and is_full_text(operand):
|
||||
code_value = lstrip_wildcard(operand)
|
||||
return [bool_op,
|
||||
('name', operator, operand, *extra),
|
||||
('code', operator, code_value, *extra),
|
||||
('code3', operator, code_value, *extra),
|
||||
('code_numeric', operator, code_value, *extra),
|
||||
]
|
||||
|
||||
def is_member(self, organization, date=None):
|
||||
"""Return if the country is in the organization at the date
|
||||
organization can be an XML id"""
|
||||
pool = Pool()
|
||||
Date = pool.get('ir.date')
|
||||
ModelData = pool.get('ir.model.data')
|
||||
Organization = pool.get('country.organization')
|
||||
if date is None:
|
||||
date = Date.today()
|
||||
if isinstance(organization, str):
|
||||
organization = ModelData.get_id(organization)
|
||||
with Transaction().set_context(date=date):
|
||||
organization = Organization(organization)
|
||||
return self in organization.countries
|
||||
|
||||
@classmethod
|
||||
def preprocess_values(cls, mode, values):
|
||||
values = super().preprocess_values(mode, values)
|
||||
for code in {'code', 'code3', 'code_numeric'}:
|
||||
if values.get(code):
|
||||
values[code] = values[code].upper()
|
||||
return values
|
||||
|
||||
|
||||
class Subdivision(DeactivableMixin, ModelSQL, ModelView):
|
||||
__name__ = 'country.subdivision'
|
||||
country = fields.Many2One(
|
||||
'country.country', "Country", required=True,
|
||||
help="The country where this subdivision is.")
|
||||
name = fields.Char(
|
||||
"Name", required=True, translate=True,
|
||||
help="The main identifier of the subdivision.")
|
||||
code = fields.Char(
|
||||
"Code",
|
||||
help="The ISO code of the subdivision.")
|
||||
flag = fields.Function(fields.Char("Flag"), 'on_change_with_flag')
|
||||
type = fields.Selection([
|
||||
(None, ""),
|
||||
('administration', 'Administration'),
|
||||
('administrative area', 'Administrative area'),
|
||||
('administrative atoll', 'Administrative atoll'),
|
||||
('administrative precinct', 'Administrative precinct'),
|
||||
('administrative region', 'Administrative Region'),
|
||||
('administrative territory', 'Administrative Territory'),
|
||||
('area', 'Area'),
|
||||
('atoll', 'Atoll'),
|
||||
('arctic region', 'Arctic Region'),
|
||||
('autonomous city', 'Autonomous City'),
|
||||
('autonomous city in north africa', 'Autonomous city in north africa'),
|
||||
('autonomous commune', 'Autonomous Commune'),
|
||||
('autonomous communities', 'Autonomous communities'),
|
||||
('autonomous community', 'Autonomous community'),
|
||||
('autonomous district', 'Autonomous District'),
|
||||
('autonomous island', 'Autonomous island'),
|
||||
('autonomous monastic state', 'Autonomous monastic state'),
|
||||
('autonomous municipality', 'Autonomous municipality'),
|
||||
('autonomous province', 'Autonomous Province'),
|
||||
('autonomous region', 'Autonomous Region'),
|
||||
('autonomous republic', 'Autonomous republic'),
|
||||
('autonomous sector', 'Autonomous sector'),
|
||||
('autonomous territory', 'Autonomous territory'),
|
||||
('autonomous territorial unit', 'Autonomous territorial unit'),
|
||||
('borough', 'Borough'),
|
||||
('canton', 'Canton'),
|
||||
('capital', 'Capital'),
|
||||
('capital city', 'Capital city'),
|
||||
('capital district', 'Capital District'),
|
||||
('capital metropolitan city', 'Capital Metropolitan City'),
|
||||
('capital territory', 'Capital Territory'),
|
||||
('chain (of islands)', 'Chain (of islands)'),
|
||||
('chains (of islands)', 'Chains (of islands)'),
|
||||
('city', 'City'),
|
||||
('city corporation', 'City corporation'),
|
||||
('city municipality', 'City municipality'),
|
||||
('city with county rights', 'City with county rights'),
|
||||
('commune', 'Commune'),
|
||||
('constitutional province', 'Constitutional province'),
|
||||
('council area', 'Council area'),
|
||||
('country', 'Country'),
|
||||
('county', 'County'),
|
||||
('decentralized regional entity', 'Decentralized regional entity'),
|
||||
('department', 'Department'),
|
||||
('dependency', 'Dependency'),
|
||||
('development region', 'Development region'),
|
||||
('district', 'District'),
|
||||
('district council area', 'District council area'),
|
||||
('district municipality', 'District municipality'),
|
||||
('districts under republic administration',
|
||||
'Districts under republic administration'),
|
||||
('district with special status', 'District with special status'),
|
||||
('division', 'Division'),
|
||||
('economic prefecture', 'Economic Prefecture'),
|
||||
('economic region', 'Economic region'),
|
||||
('emirate', 'Emirate'),
|
||||
('entity', 'Entity'),
|
||||
('european collectivity', "European collectivity"),
|
||||
('federal capital territory', 'Federal capital territory'),
|
||||
('federal dependency', 'Federal Dependency'),
|
||||
('federal district', 'Federal District'),
|
||||
('federal entity', "Federal entity"),
|
||||
('federal territories', 'Federal Territories'),
|
||||
('federal territory', 'Federal Territory'),
|
||||
('free municipal consortium', 'Free municipal consortium'),
|
||||
('geographical entity', 'Geographical entity'),
|
||||
('geographical region', 'Geographical region'),
|
||||
('geographical unit', 'Geographical unit'),
|
||||
('governorate', 'Governorate'),
|
||||
('group of islands (20 inhabited islands)',
|
||||
'Group of islands (20 inhabited islands)'),
|
||||
('included for completeness', 'Included for completeness'),
|
||||
('indigenous region', 'Indigenous region'),
|
||||
('island', 'Island'),
|
||||
('island council', 'Island council'),
|
||||
('island group', 'Island group'),
|
||||
('islands, groups of islands', 'Islands, groups of islands'),
|
||||
('land', 'Land'),
|
||||
('local council', 'Local council'),
|
||||
('london borough', 'London borough'),
|
||||
('metropolitan administration', 'Metropolitan administration'),
|
||||
('metropolitan city', 'Metropolitan city'),
|
||||
('metropolitan cities', 'Metropolitan cities'),
|
||||
('metropolitan collectivity with special status',
|
||||
'Metropolitan collectivity with special status'),
|
||||
('metropolitan department', 'Metropolitan department'),
|
||||
('metropolitan district', 'Metropolitan district'),
|
||||
('metropolitan region', 'Metropolitan region'),
|
||||
('municipalities', 'Municipalities'),
|
||||
('municipality', 'Municipality'),
|
||||
('nation', 'Nation'),
|
||||
('oblast', 'Oblast'),
|
||||
('outlying area', 'Outlying area'),
|
||||
('overseas collectivity', 'Overseas collectivity'),
|
||||
('overseas collectivity with special status',
|
||||
'Overseas collectivity with special status'),
|
||||
('overseas department', 'Overseas department'),
|
||||
('overseas departmental collectivity',
|
||||
"Overseas departmental collectivity"),
|
||||
('overseas region', 'Overseas region'),
|
||||
('overseas region/department', 'Overseas region/department'),
|
||||
('overseas territory', 'Overseas territory'),
|
||||
('overseas territorial collectivity',
|
||||
'Overseas territorial collectivity'),
|
||||
('overseas unique territorial collectivity',
|
||||
"Overseas unique territorial collectivity"),
|
||||
('pakistan administered area', 'Pakistan administered area'),
|
||||
('parish', 'Parish'),
|
||||
('popularate', 'Popularate'),
|
||||
('popularates', 'Popularates'),
|
||||
('prefecture', 'Prefecture'),
|
||||
('principality', 'Principality'),
|
||||
('province', 'Province'),
|
||||
('quarter', 'Quarter'),
|
||||
('rayon', 'Rayon'),
|
||||
('region', 'Region'),
|
||||
('regional council', 'Regional council'),
|
||||
('regional state', 'Regional state'),
|
||||
('republic', 'Republic'),
|
||||
('republican city', 'Republican City'),
|
||||
('rural municipality', 'Rural municipality'),
|
||||
('self-governed part', 'Self-governed part'),
|
||||
('special administrative city', 'Special administrative city'),
|
||||
('special administrative region', 'Special administrative region'),
|
||||
('special city', 'Special city'),
|
||||
('special district', 'Special District'),
|
||||
('special island authority', 'Special island authority'),
|
||||
('special municipality', 'Special Municipality'),
|
||||
('special region', 'Special Region'),
|
||||
('special self-governing city', 'Special self-governing city'),
|
||||
('special self-governing province', 'Special self-governing province'),
|
||||
('special zone', 'Special zone'),
|
||||
('state', 'State'),
|
||||
('state city', "State city"),
|
||||
('territorial unit', 'Territorial unit'),
|
||||
('territory', 'Territory'),
|
||||
('town', 'Town'),
|
||||
('town council', 'Town council'),
|
||||
('two-tier county', 'Two-tier county'),
|
||||
('union territory', 'Union territory'),
|
||||
('unitary authority', 'Unitary authority'),
|
||||
('unitary authority (england)', 'Unitary authority (england)'),
|
||||
('unitary authority (wales)', 'Unitary authority (wales)'),
|
||||
('urban community', 'Urban community'),
|
||||
('urban municipality', 'Urban municipality'),
|
||||
('voivodship', 'Voivodship'),
|
||||
('ward', 'Ward'),
|
||||
('zone', 'zone'),
|
||||
], "Type")
|
||||
parent = fields.Many2One('country.subdivision', 'Parent',
|
||||
domain=[
|
||||
('country', '=', Eval('country', -1)),
|
||||
],
|
||||
help="Add subdivision below the parent.")
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls._order.insert(0, ('code', 'ASC'))
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module_name):
|
||||
super().__register__(module_name)
|
||||
|
||||
table_h = cls.__table_handler__(module_name)
|
||||
|
||||
# Migration from 6.2: remove type required
|
||||
table_h.not_null_action('type', action='remove')
|
||||
|
||||
# Migration from 6.4: remove required on code
|
||||
table_h.not_null_action('code', action='remove')
|
||||
|
||||
@fields.depends('code')
|
||||
def on_change_with_flag(self, name=None):
|
||||
if self.code:
|
||||
return '🏴' + ''.join(map(chr, map(
|
||||
lambda c: 917504 + ord(c),
|
||||
self.code.replace('-', '').lower()))) + '\U000e007f'
|
||||
|
||||
@classmethod
|
||||
def search_rec_name(cls, name, clause):
|
||||
_, operator, operand, *extra = clause
|
||||
if operator.startswith('!') or operator.startswith('not '):
|
||||
bool_op = 'AND'
|
||||
else:
|
||||
bool_op = 'OR'
|
||||
code_value = operand
|
||||
if operator.endswith('like') and is_full_text(operand):
|
||||
code_value = lstrip_wildcard(operand)
|
||||
return [bool_op,
|
||||
('name', operator, operand, *extra),
|
||||
('code', operator, code_value, *extra),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def domain_code(cls, domain, tables):
|
||||
table, _ = tables[None]
|
||||
|
||||
_, op, value = domain
|
||||
Operator = fields.SQL_OPERATORS[op]
|
||||
column = cls.code.sql_column(table)
|
||||
if op.endswith('like'):
|
||||
if op.endswith('ilike') and cls.code.search_unaccented:
|
||||
database = Transaction().database
|
||||
column = database.unaccent(column)
|
||||
value = database.unaccent(value)
|
||||
bool_op = operator.and_ if op.startswith('not ') else operator.or_
|
||||
return bool_op(
|
||||
Operator(column, value),
|
||||
Operator(
|
||||
Substring(column, Position('-', column) + Literal(1)),
|
||||
value))
|
||||
return Operator(column, value)
|
||||
|
||||
@classmethod
|
||||
def preprocess_values(cls, mode, values):
|
||||
values = super().preprocess_values(mode, values)
|
||||
if values.get('code'):
|
||||
values['code'] = values['code'].upper()
|
||||
return values
|
||||
|
||||
|
||||
class PostalCode(ModelSQL, ModelView):
|
||||
__name__ = 'country.postal_code'
|
||||
country = fields.Many2One(
|
||||
'country.country', "Country", required=True, ondelete='CASCADE',
|
||||
help="The country that contains the postal code.")
|
||||
subdivision = fields.Many2One(
|
||||
'country.subdivision', "Subdivision", ondelete='CASCADE',
|
||||
domain=[('country', '=', Eval('country', -1))],
|
||||
help="The subdivision where the postal code is.")
|
||||
postal_code = fields.Char('Postal Code')
|
||||
city = fields.Char(
|
||||
"City", help="The city associated with the postal code.")
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls._order.insert(0, ('country', 'ASC'))
|
||||
cls._order.insert(0, ('postal_code', 'ASC'))
|
||||
|
||||
def get_rec_name(self, name):
|
||||
if self.city and self.postal_code:
|
||||
return '%s (%s)' % (self.city, self.postal_code)
|
||||
else:
|
||||
return (self.postal_code or self.city or str(self.id))
|
||||
|
||||
@classmethod
|
||||
def search_rec_name(cls, name, clause):
|
||||
_, operator, operand, *extra = clause
|
||||
if operator.startswith('!') or operator.startswith('not '):
|
||||
bool_op = 'AND'
|
||||
else:
|
||||
bool_op = 'OR'
|
||||
code_value = operand
|
||||
if operator.endswith('like') and is_full_text(operand):
|
||||
code_value = lstrip_wildcard(operand)
|
||||
return [bool_op,
|
||||
('postal_code', operator, code_value, *extra),
|
||||
('city', operator, operand, *extra),
|
||||
]
|
||||
297
modules/country/country.xml
Normal file
297
modules/country/country.xml
Normal file
@@ -0,0 +1,297 @@
|
||||
<?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>
|
||||
<record model="ir.ui.icon" id="country_icon">
|
||||
<field name="name">tryton-country</field>
|
||||
<field name="path">icons/tryton-country.svg</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
name="Countries"
|
||||
parent="ir.menu_administration"
|
||||
sequence="30"
|
||||
id="menu_country"
|
||||
icon="tryton-country"/>
|
||||
<record model="ir.ui.menu-res.group"
|
||||
id="menu_country_group_admin">
|
||||
<field name="menu" ref="menu_country"/>
|
||||
<field name="group" ref="res.group_admin"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="organization_view_form">
|
||||
<field name="model">country.organization</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">organization_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="organization_view_list">
|
||||
<field name="model">country.organization</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">organization_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_organization_form">
|
||||
<field name="name">Organizations</field>
|
||||
<field name="res_model">country.organization</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_organization_form_view1">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="organization_view_list"/>
|
||||
<field name="act_window" ref="act_organization_form"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_organization_form_view2">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="organization_view_form"/>
|
||||
<field name="act_window" ref="act_organization_form"/>
|
||||
</record>
|
||||
<menuitem
|
||||
parent="menu_country"
|
||||
action="act_organization_form"
|
||||
sequence="20"
|
||||
id="menu_organization_form"/>
|
||||
|
||||
<record model="ir.model.access" id="access_organization">
|
||||
<field name="model">country.organization</field>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_delete" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.model.access" id="access_organization_admin">
|
||||
<field name="model">country.organization</field>
|
||||
<field name="group" ref="res.group_admin"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_delete" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="organization_member_view_form">
|
||||
<field name="model">country.organization.member</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">organization_member_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="organization_member_view_list">
|
||||
<field name="model">country.organization.member</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">organization_member_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="region_view_form">
|
||||
<field name="model">country.region</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">region_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="region_view_list">
|
||||
<field name="model">country.region</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="priority" eval="10"/>
|
||||
<field name="name">region_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="region_view_tree">
|
||||
<field name="model">country.region</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="priority" eval="20"/>
|
||||
<field name="field_childs">subregions</field>
|
||||
<field name="name">region_tree</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_region_tree">
|
||||
<field name="name">Areas</field>
|
||||
<field name="res_model">country.region</field>
|
||||
<field name="domain" eval="[('parent', '=', None)]" pyson="1"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_region_tree_view1">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="region_view_tree"/>
|
||||
<field name="act_window" ref="act_region_tree"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_region_tree_view2">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="region_view_form"/>
|
||||
<field name="act_window" ref="act_region_tree"/>
|
||||
</record>
|
||||
<menuitem
|
||||
parent="menu_country"
|
||||
action="act_region_tree"
|
||||
sequence="20"
|
||||
id="menu_region_tree"/>
|
||||
|
||||
<record model="ir.action.act_window" id="act_region_form">
|
||||
<field name="name">Regions</field>
|
||||
<field name="res_model">country.region</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_region_form_view1">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="region_view_list"/>
|
||||
<field name="act_window" ref="act_region_form"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_region_form_view2">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="region_view_form"/>
|
||||
<field name="act_window" ref="act_region_form"/>
|
||||
</record>
|
||||
<menuitem
|
||||
parent="menu_region_tree"
|
||||
action="act_region_form"
|
||||
sequence="10"
|
||||
id="menu_region_form"/>
|
||||
|
||||
<record model="ir.model.access" id="access_region">
|
||||
<field name="model">country.region</field>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_delete" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.model.access" id="access_region_admin">
|
||||
<field name="model">country.region</field>
|
||||
<field name="group" ref="res.group_admin"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_delete" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="country_view_form">
|
||||
<field name="model">country.country</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">country_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="country_view_tree">
|
||||
<field name="model">country.country</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">country_tree</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window" id="act_country_form">
|
||||
<field name="name">Countries</field>
|
||||
<field name="res_model">country.country</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_country_form_view1">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="country_view_tree"/>
|
||||
<field name="act_window" ref="act_country_form"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_country_form_view2">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="country_view_form"/>
|
||||
<field name="act_window" ref="act_country_form"/>
|
||||
</record>
|
||||
<menuitem
|
||||
parent="menu_country"
|
||||
action="act_country_form"
|
||||
sequence="10"
|
||||
id="menu_country_form"/>
|
||||
|
||||
<record model="ir.action.act_window" id="act_country_by_region">
|
||||
<field name="name">Countries by Region</field>
|
||||
<field name="res_model">country.country</field>
|
||||
<field
|
||||
name="domain"
|
||||
eval="[('region', 'child_of', Eval('active_ids', []), 'parent')]"
|
||||
pyson="1"/>
|
||||
</record>
|
||||
<record model="ir.action.keyword" id="act_country_by_region_keyword1">
|
||||
<field name="keyword">tree_open</field>
|
||||
<field name="model">country.region,-1</field>
|
||||
<field name="action" ref="act_country_by_region"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.model.access" id="access_country">
|
||||
<field name="model">country.country</field>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_delete" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.model.access" id="access_country_admin">
|
||||
<field name="model">country.country</field>
|
||||
<field name="group" ref="res.group_admin"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_delete" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="subdivision_view_form">
|
||||
<field name="model">country.subdivision</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">subdivision_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="subdivision_view_tree">
|
||||
<field name="model">country.subdivision</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">subdivision_tree</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.model.access" id="access_subdivision">
|
||||
<field name="model">country.subdivision</field>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_delete" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.model.access" id="access_subdivision_admin">
|
||||
<field name="model">country.subdivision</field>
|
||||
<field name="group" ref="res.group_admin"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_delete" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="postal_code_view_form">
|
||||
<field name="model">country.postal_code</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">postal_code_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="postal_code_view_list">
|
||||
<field name="model">country.postal_code</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">postal_code_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_postal_code_form">
|
||||
<field name="name">Postal Codes</field>
|
||||
<field name="res_model">country.postal_code</field>
|
||||
<field name="domain"
|
||||
eval="[('country', 'in', Eval('active_ids'))]" pyson="1"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_postal_code_form_view1">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="postal_code_view_list"/>
|
||||
<field name="act_window" ref="act_postal_code_form"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_postal_code_form_view2">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="postal_code_view_form"/>
|
||||
<field name="act_window" ref="act_postal_code_form"/>
|
||||
</record>
|
||||
<record model="ir.action.keyword" id="act_postal_code_form_keyword1">
|
||||
<field name="keyword">form_relate</field>
|
||||
<field name="model">country.country,-1</field>
|
||||
<field name="action" ref="act_postal_code_form"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.model.access" id="access_postal_code">
|
||||
<field name="model">country.postal_code</field>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_delete" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.model.access" id="access_postal_code_admin">
|
||||
<field name="model">country.postal_code</field>
|
||||
<field name="group" ref="res.group_admin"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_delete" eval="True"/>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
4
modules/country/icons/tryton-country.svg
Normal file
4
modules/country/icons/tryton-country.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M14.4 6L14 4H5v17h2v-7h5.6l.4 2h7V6z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 186 B |
1113
modules/country/locale/bg.po
Normal file
1113
modules/country/locale/bg.po
Normal file
File diff suppressed because it is too large
Load Diff
1023
modules/country/locale/ca.po
Normal file
1023
modules/country/locale/ca.po
Normal file
File diff suppressed because it is too large
Load Diff
1095
modules/country/locale/cs.po
Normal file
1095
modules/country/locale/cs.po
Normal file
File diff suppressed because it is too large
Load Diff
1023
modules/country/locale/de.po
Normal file
1023
modules/country/locale/de.po
Normal file
File diff suppressed because it is too large
Load Diff
1023
modules/country/locale/es.po
Normal file
1023
modules/country/locale/es.po
Normal file
File diff suppressed because it is too large
Load Diff
1091
modules/country/locale/es_419.po
Normal file
1091
modules/country/locale/es_419.po
Normal file
File diff suppressed because it is too large
Load Diff
1111
modules/country/locale/et.po
Normal file
1111
modules/country/locale/et.po
Normal file
File diff suppressed because it is too large
Load Diff
1111
modules/country/locale/fa.po
Normal file
1111
modules/country/locale/fa.po
Normal file
File diff suppressed because it is too large
Load Diff
1092
modules/country/locale/fi.po
Normal file
1092
modules/country/locale/fi.po
Normal file
File diff suppressed because it is too large
Load Diff
1023
modules/country/locale/fr.po
Normal file
1023
modules/country/locale/fr.po
Normal file
File diff suppressed because it is too large
Load Diff
1108
modules/country/locale/hu.po
Normal file
1108
modules/country/locale/hu.po
Normal file
File diff suppressed because it is too large
Load Diff
1041
modules/country/locale/id.po
Normal file
1041
modules/country/locale/id.po
Normal file
File diff suppressed because it is too large
Load Diff
1100
modules/country/locale/it.po
Normal file
1100
modules/country/locale/it.po
Normal file
File diff suppressed because it is too large
Load Diff
1096
modules/country/locale/lo.po
Normal file
1096
modules/country/locale/lo.po
Normal file
File diff suppressed because it is too large
Load Diff
1110
modules/country/locale/lt.po
Normal file
1110
modules/country/locale/lt.po
Normal file
File diff suppressed because it is too large
Load Diff
1023
modules/country/locale/nl.po
Normal file
1023
modules/country/locale/nl.po
Normal file
File diff suppressed because it is too large
Load Diff
1034
modules/country/locale/pl.po
Normal file
1034
modules/country/locale/pl.po
Normal file
File diff suppressed because it is too large
Load Diff
1023
modules/country/locale/pt.po
Normal file
1023
modules/country/locale/pt.po
Normal file
File diff suppressed because it is too large
Load Diff
1110
modules/country/locale/ro.po
Normal file
1110
modules/country/locale/ro.po
Normal file
File diff suppressed because it is too large
Load Diff
1104
modules/country/locale/ru.po
Normal file
1104
modules/country/locale/ru.po
Normal file
File diff suppressed because it is too large
Load Diff
1034
modules/country/locale/sl.po
Normal file
1034
modules/country/locale/sl.po
Normal file
File diff suppressed because it is too large
Load Diff
1085
modules/country/locale/tr.po
Normal file
1085
modules/country/locale/tr.po
Normal file
File diff suppressed because it is too large
Load Diff
1053
modules/country/locale/uk.po
Normal file
1053
modules/country/locale/uk.po
Normal file
File diff suppressed because it is too large
Load Diff
1031
modules/country/locale/zh_CN.po
Normal file
1031
modules/country/locale/zh_CN.po
Normal file
File diff suppressed because it is too large
Load Diff
101
modules/country/organization.xml
Normal file
101
modules/country/organization.xml
Normal file
@@ -0,0 +1,101 @@
|
||||
<?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 grouped="1">
|
||||
<record model="country.organization" id="organization_eu">
|
||||
<field name="name">European Union</field>
|
||||
<field name="code">EU</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_benelux">
|
||||
<field name="name">Benelux Union</field>
|
||||
<field name="code">Benelux</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_nafta">
|
||||
<field name="name">North American Free Trade Agreement</field>
|
||||
<field name="code">NAFTA</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_mercosur">
|
||||
<field name="name">Southern Common Market</field>
|
||||
<field name="code">Mercosur</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_can">
|
||||
<field name="name">Andean Community</field>
|
||||
<field name="code">CAN</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_caricom">
|
||||
<field name="name">Caribbean Community</field>
|
||||
<field name="code">CARICOM</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_apec">
|
||||
<field name="name">Asia-Pacific Economic Cooperation</field>
|
||||
<field name="code">APEC</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_asean">
|
||||
<field name="name">Association of Southeast Asian Nations</field>
|
||||
<field name="code">ASEAN</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_safta">
|
||||
<field name="name">South Asian Free Trade Area</field>
|
||||
<field name="code">SAFTA</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_gcc">
|
||||
<field name="name">Cooperation Council for the Arab States of the Gulf</field>
|
||||
<field name="code">GCC</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_cemac">
|
||||
<field name="name">Economic and Monetary Community of Central Africa</field>
|
||||
<field name="code">CEMAC</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_eccas">
|
||||
<field name="name">Economic Community of Central African States</field>
|
||||
<field name="code">ECCAS</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_ecowas">
|
||||
<field name="name">Economic Community of West African States</field>
|
||||
<field name="code">ECOWAS</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_cen-sad">
|
||||
<field name="name">Community of Sahel–Saharan States</field>
|
||||
<field name="code">CEN-SAD</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_comesa">
|
||||
<field name="name">Common Market for Eastern and Southern Africa</field>
|
||||
<field name="code">COMESA</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_eac">
|
||||
<field name="name">East African Community</field>
|
||||
<field name="code">EAC</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_igad">
|
||||
<field name="name">Intergovernmental Authority on Development</field>
|
||||
<field name="code">IGAD</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_sadc">
|
||||
<field name="name">Southern African Development Community</field>
|
||||
<field name="code">SADC</field>
|
||||
</record>
|
||||
|
||||
<record model="country.organization" id="organization_amu">
|
||||
<field name="name">Arab Maghreb Union</field>
|
||||
<field name="code">AMU</field>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
206
modules/country/region.xml
Normal file
206
modules/country/region.xml
Normal file
@@ -0,0 +1,206 @@
|
||||
<?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 grouped="1">
|
||||
<record model="country.region" id="region_world">
|
||||
<field name="name">World</field>
|
||||
<field name="code_numeric">001</field>
|
||||
</record>
|
||||
</data>
|
||||
<data grouped="1">
|
||||
<record model="country.region" id="region_africa">
|
||||
<field name="name">Africa</field>
|
||||
<field name="code_numeric">002</field>
|
||||
<field name="parent" ref="region_world"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_antarctica">
|
||||
<field name="name">Antarctica</field>
|
||||
<field name="code_numeric">010</field>
|
||||
<field name="parent" ref="region_world"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_americas">
|
||||
<field name="name">Americas</field>
|
||||
<field name="code_numeric">019</field>
|
||||
<field name="parent" ref="region_world"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_asia">
|
||||
<field name="name">Asia</field>
|
||||
<field name="code_numeric">142</field>
|
||||
<field name="parent" ref="region_world"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_europe">
|
||||
<field name="name">Europe</field>
|
||||
<field name="code_numeric">150</field>
|
||||
<field name="parent" ref="region_world"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_oceania">
|
||||
<field name="name">Oceania</field>
|
||||
<field name="code_numeric">009</field>
|
||||
<field name="parent" ref="region_world"/>
|
||||
</record>
|
||||
</data>
|
||||
<data grouped="1">
|
||||
<record model="country.region" id="region_northern_africa">
|
||||
<field name="name">Northern Africa</field>
|
||||
<field name="code_numeric">015</field>
|
||||
<field name="parent" ref="region_africa"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_sub-saharan_africa">
|
||||
<field name="name">Sub-Saharan Africa</field>
|
||||
<field name="code_numeric">202</field>
|
||||
<field name="parent" ref="region_africa"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_north_america">
|
||||
<field name="name">North America</field>
|
||||
<field name="code_numeric">003</field>
|
||||
<field name="parent" ref="region_americas"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_latin_america_caribbean">
|
||||
<field name="name">Latin America and the Caribbean</field>
|
||||
<field name="code_numeric">419</field>
|
||||
<field name="parent" ref="region_americas"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_eastern_asia">
|
||||
<field name="name">Eastern Asia</field>
|
||||
<field name="code_numeric">030</field>
|
||||
<field name="parent" ref="region_asia"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_southern_asia">
|
||||
<field name="name">Southern Asia</field>
|
||||
<field name="code_numeric">034</field>
|
||||
<field name="parent" ref="region_asia"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_south-eastern_asia">
|
||||
<field name="name">South-eastern Asia</field>
|
||||
<field name="code_numeric">035</field>
|
||||
<field name="parent" ref="region_asia"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_central_asia">
|
||||
<field name="name">Central Asia</field>
|
||||
<field name="code_numeric">143</field>
|
||||
<field name="parent" ref="region_asia"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_western_asia">
|
||||
<field name="name">Western Asia</field>
|
||||
<field name="code_numeric">145</field>
|
||||
<field name="parent" ref="region_asia"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_southern_europe">
|
||||
<field name="name">Southern Europe</field>
|
||||
<field name="code_numeric">039</field>
|
||||
<field name="parent" ref="region_europe"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_eastern_europe">
|
||||
<field name="name">Eastern Europe</field>
|
||||
<field name="code_numeric">151</field>
|
||||
<field name="parent" ref="region_europe"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_northern_europe">
|
||||
<field name="name">Northern Europe</field>
|
||||
<field name="code_numeric">154</field>
|
||||
<field name="parent" ref="region_europe"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_western_europe">
|
||||
<field name="name">Western Europe</field>
|
||||
<field name="code_numeric">155</field>
|
||||
<field name="parent" ref="region_europe"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_australia_new_zealand">
|
||||
<field name="name">Australia and New Zealand</field>
|
||||
<field name="code_numeric">053</field>
|
||||
<field name="parent" ref="region_oceania"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_melanesia">
|
||||
<field name="name">Melanesia</field>
|
||||
<field name="code_numeric">054</field>
|
||||
<field name="parent" ref="region_oceania"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_micronesia">
|
||||
<field name="name">Micronesia</field>
|
||||
<field name="code_numeric">057</field>
|
||||
<field name="parent" ref="region_oceania"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_polynesia">
|
||||
<field name="name">Polynesia</field>
|
||||
<field name="code_numeric">061</field>
|
||||
<field name="parent" ref="region_oceania"/>
|
||||
</record>
|
||||
</data>
|
||||
<data grouped="1">
|
||||
<record model="country.region" id="region_western_africa">
|
||||
<field name="name">Western Africa</field>
|
||||
<field name="code_numeric">011</field>
|
||||
<field name="parent" ref="region_sub-saharan_africa"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_eastern_africa">
|
||||
<field name="name">Eastern Africa</field>
|
||||
<field name="code_numeric">014</field>
|
||||
<field name="parent" ref="region_sub-saharan_africa"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_middle_africa">
|
||||
<field name="name">Middle Africa</field>
|
||||
<field name="code_numeric">017</field>
|
||||
<field name="parent" ref="region_sub-saharan_africa"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_southern_africa">
|
||||
<field name="name">Southern Africa</field>
|
||||
<field name="code_numeric">018</field>
|
||||
<field name="parent" ref="region_sub-saharan_africa"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_northern_america">
|
||||
<field name="name">Northern America</field>
|
||||
<field name="code_numeric">021</field>
|
||||
<field name="parent" ref="region_north_america"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_south_america">
|
||||
<field name="name">South America</field>
|
||||
<field name="code_numeric">005</field>
|
||||
<field name="parent" ref="region_latin_america_caribbean"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_central_america">
|
||||
<field name="name">Central America</field>
|
||||
<field name="code_numeric">013</field>
|
||||
<field name="parent" ref="region_latin_america_caribbean"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_caribbean">
|
||||
<field name="name">Caribbean</field>
|
||||
<field name="code_numeric">029</field>
|
||||
<field name="parent" ref="region_latin_america_caribbean"/>
|
||||
</record>
|
||||
|
||||
<record model="country.region" id="region_channel_islands">
|
||||
<field name="name">Channel Islands</field>
|
||||
<field name="code_numeric">830</field>
|
||||
<field name="parent" ref="region_northern_europe"/>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
2
modules/country/scripts/__init__.py
Normal file
2
modules/country/scripts/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
BIN
modules/country/scripts/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
modules/country/scripts/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
565
modules/country/scripts/import_countries.py
Normal file
565
modules/country/scripts/import_countries.py
Normal file
@@ -0,0 +1,565 @@
|
||||
#!/usr/bin/env python3
|
||||
# PYTHON_ARGCOMPLETE_OK
|
||||
# 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 datetime as dt
|
||||
import gettext
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import pycountry
|
||||
|
||||
try:
|
||||
import argcomplete
|
||||
except ImportError:
|
||||
argcomplete = None
|
||||
|
||||
try:
|
||||
from tqdm import tqdm
|
||||
except ImportError:
|
||||
tqdm = None
|
||||
|
||||
try:
|
||||
from proteus import Model, config
|
||||
except ImportError:
|
||||
prog = os.path.basename(sys.argv[0])
|
||||
sys.exit("proteus must be installed to use %s" % prog)
|
||||
|
||||
ORGANIZATIONS = {
|
||||
# Founding members has no from date
|
||||
'EU': {
|
||||
'AT': [(dt.date(1995, 1, 1), None)],
|
||||
'BE': [(None, None)],
|
||||
'BG': [(dt.date(2007, 1, 1), None)],
|
||||
'CY': [(dt.date(2004, 5, 1), None)],
|
||||
'CZ': [(dt.date(2004, 5, 1), None)],
|
||||
'DE': [(None, None)],
|
||||
'DK': [(dt.date(1973, 1, 1), None)],
|
||||
'EE': [(dt.date(2004, 5, 1), None)],
|
||||
'ES': [(dt.date(1986, 1, 1), None)],
|
||||
'FI': [(dt.date(1995, 1, 1), None)],
|
||||
'FR': [(None, None)],
|
||||
'GB': [(dt.date(1973, 1, 1), dt.date(2020, 1, 31))],
|
||||
'GR': [(dt.date(1981, 1, 1), None)],
|
||||
'HR': [(dt.date(2013, 7, 1), None)],
|
||||
'HU': [(dt.date(2004, 5, 1), None)],
|
||||
'IE': [(dt.date(1973, 1, 1), None)],
|
||||
'IT': [(None, None)],
|
||||
'LT': [(dt.date(2004, 5, 1), None)],
|
||||
'LU': [(None, None)],
|
||||
'LV': [(dt.date(2004, 5, 1), None)],
|
||||
'MT': [(dt.date(2004, 5, 1), None)],
|
||||
'NL': [(None, None)],
|
||||
'PL': [(dt.date(2004, 5, 1), None)],
|
||||
'PT': [(dt.date(1986, 1, 1), None)],
|
||||
'RO': [(dt.date(2007, 1, 1), None)],
|
||||
'SE': [(dt.date(1995, 1, 1), None)],
|
||||
'SI': [(dt.date(2004, 5, 1), None)],
|
||||
'SK': [(dt.date(2004, 5, 1), None)],
|
||||
},
|
||||
'Benelux': {
|
||||
'BE': [(None, None)],
|
||||
'LU': [(None, None)],
|
||||
'NL': [(None, None)],
|
||||
},
|
||||
'NAFTA': {
|
||||
'CA': [(None, None)],
|
||||
'MX': [(None, None)],
|
||||
'US': [(None, None)],
|
||||
},
|
||||
'Mercosur': {
|
||||
'AR': [(None, None)],
|
||||
'BR': [(None, None)],
|
||||
'PY': [(None, None)],
|
||||
'UY': [(None, None)],
|
||||
'VE': [(dt.date(2012, 7, 31), dt.date(2016, 12, 2))],
|
||||
},
|
||||
'CAN': {
|
||||
# days and months are default to covert the full year
|
||||
'BO': [(None, None)],
|
||||
'CL': [(dt.date(1969, 1, 1), dt.date(1976, 12, 31))],
|
||||
'CO': [(None, None)],
|
||||
'EC': [(None, None)],
|
||||
'PE': [(None, None)],
|
||||
'VE': [(dt.date(1973, 1, 1), dt.date(2006, 12, 31))],
|
||||
},
|
||||
'CARICOM': {
|
||||
'AG': [(dt.date(1974, 7, 4), None)],
|
||||
'BB': [(None, None)],
|
||||
'BS': [(dt.date(1983, 7, 4), None)],
|
||||
'BZ': [(dt.date(1974, 5, 1), None)],
|
||||
'DM': [(dt.date(1974, 5, 1), None)],
|
||||
'GD': [(dt.date(1974, 5, 1), None)],
|
||||
'GY': [(None, None)],
|
||||
'HT': [(dt.date(2002, 7, 2), None)],
|
||||
'JM': [(None, None)],
|
||||
'KN': [(dt.date(1974, 7, 26), None)],
|
||||
'LC': [(dt.date(1974, 5, 1), None)],
|
||||
'MS': [(dt.date(1974, 5, 1), None)],
|
||||
'SR': [(dt.date(1995, 7, 4), None)],
|
||||
'TT': [(None, None)],
|
||||
'VC': [(dt.date(1974, 5, 1), None)],
|
||||
},
|
||||
'APEC': {
|
||||
# days are default to covert the full month
|
||||
'AU': [(None, None)],
|
||||
'BN': [(None, None)],
|
||||
'CA': [(None, None)],
|
||||
'CL': [(dt.date(1994, 11, 1), None)],
|
||||
'CN': [(dt.date(1991, 11, 1), None)],
|
||||
'HK': [(dt.date(1991, 11, 1), None)],
|
||||
'ID': [(None, None)],
|
||||
'JP': [(None, None)],
|
||||
'KR': [(None, None)],
|
||||
'MX': [(dt.date(1993, 11, 1), None)],
|
||||
'MY': [(None, None)],
|
||||
'NZ': [(None, None)],
|
||||
'PE': [(dt.date(1998, 11, 1), None)],
|
||||
'PG': [(dt.date(1993, 11, 1), None)],
|
||||
'PH': [(None, None)],
|
||||
'RU': [(dt.date(1998, 11, 1), None)],
|
||||
'SG': [(None, None)],
|
||||
'TH': [(None, None)],
|
||||
'TW': [(dt.date(1991, 11, 1), None)],
|
||||
'US': [(None, None)],
|
||||
'VN': [(dt.date(1998, 11, 1), None)],
|
||||
},
|
||||
'ASEAN': {
|
||||
'BN': [(dt.date(1984, 1, 7), None)],
|
||||
'ID': [(None, None)],
|
||||
'KH': [(dt.date(1999, 4, 30), None)],
|
||||
'LA': [(dt.date(1997, 7, 23), None)],
|
||||
'MM': [(dt.date(1997, 7, 23), None)],
|
||||
'MY': [(None, None)],
|
||||
'PH': [(None, None)],
|
||||
'SG': [(None, None)],
|
||||
'TH': [(None, None)],
|
||||
'VN': [(dt.date(1995, 7, 28), None)],
|
||||
},
|
||||
'SAFTA': {
|
||||
'AF': [(None, None)],
|
||||
'BD': [(None, None)],
|
||||
'BT': [(None, None)],
|
||||
'IN': [(None, None)],
|
||||
'LK': [(None, None)],
|
||||
'MV': [(None, None)],
|
||||
'NP': [(None, None)],
|
||||
'PK': [(None, None)],
|
||||
},
|
||||
'GCC': {
|
||||
'AE': [(None, None)],
|
||||
'BH': [(None, None)],
|
||||
'KW': [(None, None)],
|
||||
'OM': [(None, None)],
|
||||
'QA': [(None, None)],
|
||||
'SA': [(None, None)],
|
||||
},
|
||||
'CEMAC': {
|
||||
'CF': [(None, None)],
|
||||
'CG': [(None, None)],
|
||||
'CM': [(None, None)],
|
||||
'GA': [(None, None)],
|
||||
'GQ': [(dt.date(1983, 12, 19), None)],
|
||||
'TD': [(None, None)],
|
||||
},
|
||||
'ECCAS': {
|
||||
'AO': [(None, None)],
|
||||
'BI': [(None, None)],
|
||||
'CM': [(None, None)],
|
||||
'CF': [(None, None)],
|
||||
'TD': [(None, None)],
|
||||
'CD': [(None, None)],
|
||||
'GQ': [(None, None)],
|
||||
'GA': [(None, None)],
|
||||
'CG': [(None, None)],
|
||||
'RW': [(None, dt.date(2007, 12, 31)), (dt.date(2016, 8, 17), None)],
|
||||
'ST': [(None, None)],
|
||||
},
|
||||
'ECOWAS': {
|
||||
'BF': [(None, dt.date(2022, 1, 28))],
|
||||
'BJ': [(None, None)],
|
||||
'CI': [(None, None)],
|
||||
'CV': [(dt.date(1977, 1, 1), None)],
|
||||
'GH': [(None, None)],
|
||||
'GM': [(None, None)],
|
||||
'GN': [(None, dt.date(2021, 9, 8))],
|
||||
'GW': [(None, None)],
|
||||
'LR': [(None, None)],
|
||||
'ML': [(None, dt.date(2021, 5, 30))],
|
||||
'MR': [(None, dt.date(2000, 12, 1))],
|
||||
'NE': [(None, None)],
|
||||
'NG': [(None, None)],
|
||||
'SL': [(None, None)],
|
||||
'SN': [(None, None)],
|
||||
'TG': [(None, None)],
|
||||
},
|
||||
'CEN-SAD': {
|
||||
# days and months are default to covert the full year
|
||||
'BF': [(None, None)],
|
||||
'BJ': [(dt.date(2002, 1, 1), None)],
|
||||
'CF': [(dt.date(1999, 1, 1), None)],
|
||||
'CI': [(dt.date(2004, 1, 1), None)],
|
||||
'CV': [(dt.date(2009, 1, 1), None)],
|
||||
'DJ': [(dt.date(2000, 1, 1), None)],
|
||||
'EG': [(dt.date(2001, 1, 1), None)],
|
||||
'ER': [(dt.date(1999, 1, 1), None)],
|
||||
'FN': [(dt.date(2007, 1, 1), None)],
|
||||
'GH': [(dt.date(2005, 1, 1), None)],
|
||||
'GM': [(dt.date(2000, 1, 1), None)],
|
||||
'GW': [(dt.date(2004, 1, 1), None)],
|
||||
'KE': [(dt.date(2007, 1, 1), None)],
|
||||
'KM': [(dt.date(2007, 1, 1), None)],
|
||||
'LR': [(dt.date(2004, 1, 1), None)],
|
||||
'LY': [(None, None)],
|
||||
'MA': [(dt.date(2001, 1, 1), None)],
|
||||
'ML': [(None, None)],
|
||||
'MR': [(dt.date(2007, 1, 1), None)],
|
||||
'NE': [(None, None)],
|
||||
'NG': [(dt.date(2001, 1, 1), None)],
|
||||
'SD': [(None, None)],
|
||||
'SL': [(dt.date(2005, 1, 1), None)],
|
||||
'SN': [(dt.date(2000, 1, 1), None)],
|
||||
'SO': [(dt.date(2001, 1, 1), None)],
|
||||
'ST': [(dt.date(2007, 1, 1), None)],
|
||||
'TD': [(None, None)],
|
||||
'TG': [(dt.date(2002, 1, 1), None)],
|
||||
'TN': [(dt.date(2001, 1, 1), None)],
|
||||
},
|
||||
'COMESA': {
|
||||
# days and months are default to covert the full year
|
||||
'AO': [(None, dt.date(2007, 1, 1))],
|
||||
'BI': [(dt.date(1981, 12, 21), None)],
|
||||
'CD': [(dt.date(1981, 12, 21), None)],
|
||||
'DJ': [(dt.date(1981, 12, 21), None)],
|
||||
'EG': [(dt.date(1999, 1, 6), None)],
|
||||
'ER': [(dt.date(1994, 1, 1), None)],
|
||||
'ET': [(dt.date(1981, 12, 21), None)],
|
||||
'KE': [(None, None)],
|
||||
'KM': [(dt.date(1981, 12, 21), None)],
|
||||
'LS': [(None, dt.date(1997, 1, 1))],
|
||||
'LY': [(dt.date(2005, 6, 3), None)],
|
||||
'MG': [(None, None)],
|
||||
'MU': [(None, None)],
|
||||
'MW': [(None, None)],
|
||||
'MZ': [(None, dt.date(1997, 1, 1))],
|
||||
'NA': [(None, dt.date(2004, 5, 2))],
|
||||
'RW': [(None, None)],
|
||||
'SC': [(dt.date(2001, 1, 1), None)],
|
||||
'SD': [(dt.date(1981, 12, 21), None)],
|
||||
'SO': [(dt.date(2018, 7, 19), None)],
|
||||
'SZ': [(dt.date(1981, 12, 21), None)],
|
||||
'TN': [(dt.date(2018, 7, 18), None)],
|
||||
'TZ': [(None, dt.date(2000, 9, 2))],
|
||||
'UG': [(None, None)],
|
||||
'ZM': [(None, None)],
|
||||
'ZW': [(None, None)],
|
||||
},
|
||||
'EAC': {
|
||||
# days and months are default to covert the full year
|
||||
'BI': [(dt.date(2007, 1, 1), None)],
|
||||
'CD': [(dt.date(2022, 1, 1), None)],
|
||||
'KE': [(None, None)],
|
||||
'RW': [(dt.date(2007, 1, 1), None)],
|
||||
'SS': [(dt.date(2012, 1, 1), None)],
|
||||
'TZ': [(None, None)],
|
||||
'UG': [(None, None)],
|
||||
},
|
||||
'IGAD': {
|
||||
# days and months are default to covert the full year
|
||||
'DJ': [(None, None)],
|
||||
'ER': [(dt.date(1993, 1, 1), dt.date(2007, 12, 31)),
|
||||
(dt.date(2011, 1, 1), None)],
|
||||
'ET': [(None, None)],
|
||||
'KE': [(None, None)],
|
||||
'SD': [(None, None)],
|
||||
'SO': [(None, None)],
|
||||
'SS': [(dt.date(2011, 1, 1), dt.date(2021, 12, 1))],
|
||||
'UG': [(None, None)],
|
||||
},
|
||||
'SADC': {
|
||||
'AO': [(None, None)],
|
||||
'BW': [(None, None)],
|
||||
'CD': [(dt.date(1997, 9, 8), None)],
|
||||
'KM': [(dt.date(2017, 1, 1), None)],
|
||||
'LS': [(None, None)],
|
||||
'MG': [(dt.date(2005, 8, 18), dt.date(2009, 1, 26)),
|
||||
(dt.date(2014, 1, 30), None)],
|
||||
'MU': [(dt.date(1995, 8, 28), None)],
|
||||
'MW': [(None, None)],
|
||||
'MZ': [(None, None)],
|
||||
'NA': [(dt.date(1990, 3, 21), None)],
|
||||
'SC': [(dt.date(1997, 9, 8), dt.date(2004, 7, 1)),
|
||||
(dt.date(2008, 1, 1), None)],
|
||||
'SZ': [(None, None)],
|
||||
'TZ': [(None, None)],
|
||||
'ZA': [(dt.date(1994, 8, 30), None)],
|
||||
'ZM': [(None, None)],
|
||||
'ZW': [(None, None)],
|
||||
},
|
||||
'AMU': {
|
||||
'DZ': [(None, None)],
|
||||
'LY': [(None, None)],
|
||||
'MA': [(None, None)],
|
||||
'MR': [(None, None)],
|
||||
'TN': [(None, None)],
|
||||
},
|
||||
}
|
||||
|
||||
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, **kwargs):
|
||||
if tqdm:
|
||||
return tqdm(iterable, disable=None, **kwargs)
|
||||
else:
|
||||
return iterable
|
||||
|
||||
|
||||
def _get_language_codes():
|
||||
Language = Model.get('ir.lang')
|
||||
languages = Language.find([('translatable', '=', True)])
|
||||
for l in languages:
|
||||
yield l.code
|
||||
|
||||
|
||||
def _remove_forbidden_chars(name):
|
||||
from trytond.tools import remove_forbidden_chars
|
||||
return remove_forbidden_chars(name)
|
||||
|
||||
|
||||
def get_countries():
|
||||
Country = Model.get('country.country')
|
||||
return {c.code: c for c in Country.find([])}
|
||||
|
||||
|
||||
def get_organizations():
|
||||
Organization = Model.get('country.organization')
|
||||
return {o.code: o for o in Organization.find([])}
|
||||
|
||||
|
||||
def update_countries(countries):
|
||||
print("Update countries", file=sys.stderr)
|
||||
Region = Model.get('country.region')
|
||||
Country = Model.get('country.country')
|
||||
Member = Model.get('country.organization.member')
|
||||
|
||||
organizations = get_organizations()
|
||||
|
||||
code2region = {a.code_numeric: a for a in Region.find([])}
|
||||
|
||||
records = []
|
||||
for country in _progress(pycountry.countries):
|
||||
code = country.alpha_2
|
||||
if code in countries:
|
||||
record = countries[code]
|
||||
else:
|
||||
record = Country(code=code, members=[])
|
||||
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))
|
||||
for organization_code, members in ORGANIZATIONS.items():
|
||||
if organization_code in organizations and code in members:
|
||||
organization = organizations[organization_code]
|
||||
dates = members[code].copy()
|
||||
for member in list(record.members):
|
||||
if member.organization == organization:
|
||||
if dates:
|
||||
member.from_date, member.to_date = dates.pop()
|
||||
else:
|
||||
record.members.remove(member)
|
||||
for from_date, to_date in dates:
|
||||
record.members.append(Member(
|
||||
organization=organization,
|
||||
from_date=from_date,
|
||||
to_date=to_date))
|
||||
records.append(record)
|
||||
|
||||
Country.save(records)
|
||||
return {c.code: c for c in records}
|
||||
|
||||
|
||||
def translate_countries(countries):
|
||||
Country = Model.get('country.country')
|
||||
|
||||
current_config = config.get_config()
|
||||
for code in _get_language_codes():
|
||||
try:
|
||||
gnutranslation = gettext.translation(
|
||||
'iso3166-1', pycountry.LOCALES_DIR, languages=[code])
|
||||
except IOError:
|
||||
continue
|
||||
print("Update countries %s" % code, file=sys.stderr)
|
||||
with current_config.set_context(language=code):
|
||||
records = []
|
||||
for country in _progress(pycountry.countries):
|
||||
record = Country(countries[country.alpha_2].id)
|
||||
record.name = _remove_forbidden_chars(
|
||||
gnutranslation.gettext(country.name))
|
||||
records.append(record)
|
||||
Country.save(records)
|
||||
|
||||
|
||||
def get_subdivisions():
|
||||
Subdivision = Model.get('country.subdivision')
|
||||
return {(s.country.code, s.code): s for s in Subdivision.find([])}
|
||||
|
||||
|
||||
def update_subdivisions(countries, subdivisions):
|
||||
print("Update subdivisions", file=sys.stderr)
|
||||
Subdivision = Model.get('country.subdivision')
|
||||
|
||||
types = dict(Subdivision._fields['type']['selection'])
|
||||
unknown_types = set()
|
||||
records = []
|
||||
for subdivision in _progress(pycountry.subdivisions):
|
||||
code = subdivision.code
|
||||
country_code = subdivision.country_code
|
||||
if (country_code, code) in subdivisions:
|
||||
record = subdivisions[(country_code, code)]
|
||||
else:
|
||||
record = Subdivision(code=code, country=countries[country_code])
|
||||
record.name = _remove_forbidden_chars(subdivision.name)
|
||||
type_ = subdivision.type.lower()
|
||||
if type_ in types:
|
||||
record.type = subdivision.type.lower()
|
||||
else:
|
||||
record.type = None
|
||||
if type_ not in unknown_types:
|
||||
warnings.warn(
|
||||
f"Unknown subdivision type: {subdivision.type!r}")
|
||||
unknown_types.add(type_)
|
||||
records.append(record)
|
||||
|
||||
Subdivision.save(records)
|
||||
return {(s.country.code, s.code): s for s in records}
|
||||
|
||||
|
||||
def update_subdivisions_parent(subdivisions):
|
||||
print("Update subdivisions parent", file=sys.stderr)
|
||||
Subdivision = Model.get('country.subdivision')
|
||||
|
||||
records = []
|
||||
for subdivision in _progress(pycountry.subdivisions):
|
||||
code = subdivision.code
|
||||
country_code = subdivision.country_code
|
||||
record = subdivisions[(country_code, code)]
|
||||
if subdivision.parent:
|
||||
record.parent = subdivisions[
|
||||
(country_code, subdivision.parent.code)]
|
||||
else:
|
||||
record.parent = None
|
||||
records.append(record)
|
||||
Subdivision.save(records)
|
||||
|
||||
|
||||
def translate_subdivisions(subdivisions):
|
||||
Subdivision = Model.get('country.subdivision')
|
||||
|
||||
current_config = config.get_config()
|
||||
for code in _get_language_codes():
|
||||
try:
|
||||
gnutranslation = gettext.translation(
|
||||
'iso3166-2', pycountry.LOCALES_DIR, languages=[code])
|
||||
except IOError:
|
||||
continue
|
||||
print("Update subdivisions %s" % code, file=sys.stderr)
|
||||
with current_config.set_context(language=code):
|
||||
records = []
|
||||
for subdivision in _progress(pycountry.subdivisions):
|
||||
record = Subdivision(subdivisions[
|
||||
(subdivision.country_code, subdivision.code)].id)
|
||||
record.name = _remove_forbidden_chars(
|
||||
gnutranslation.gettext(subdivision.name))
|
||||
records.append(record)
|
||||
Subdivision.save(records)
|
||||
|
||||
|
||||
def main(database, config_file=None):
|
||||
config.set_trytond(database, config_file=config_file)
|
||||
with config.get_config().set_context(active_test=False):
|
||||
do_import()
|
||||
|
||||
|
||||
def do_import():
|
||||
countries = get_countries()
|
||||
countries = update_countries(countries)
|
||||
translate_countries(countries)
|
||||
subdivisions = get_subdivisions()
|
||||
subdivisions = update_subdivisions(countries, subdivisions)
|
||||
update_subdivisions_parent(subdivisions)
|
||||
translate_subdivisions(subdivisions)
|
||||
|
||||
|
||||
def run():
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('-d', '--database', dest='database', required=True)
|
||||
parser.add_argument('-c', '--config', dest='config_file',
|
||||
help='the trytond config file')
|
||||
if argcomplete:
|
||||
argcomplete.autocomplete(parser)
|
||||
|
||||
args = parser.parse_args()
|
||||
main(args.database, args.config_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
142
modules/country/scripts/import_postal_codes.py
Normal file
142
modules/country/scripts/import_postal_codes.py
Normal file
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env python
|
||||
# PYTHON_ARGCOMPLETE_OK
|
||||
# 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 __future__ import print_function
|
||||
|
||||
import csv
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
from urllib.error import HTTPError
|
||||
from urllib.request import urlopen
|
||||
except ImportError:
|
||||
from urllib2 import urlopen, HTTPError
|
||||
|
||||
import zipfile
|
||||
from argparse import ArgumentParser
|
||||
from io import BytesIO, TextIOWrapper
|
||||
|
||||
try:
|
||||
import argcomplete
|
||||
except ImportError:
|
||||
argcomplete = None
|
||||
|
||||
try:
|
||||
from tqdm import tqdm
|
||||
except ImportError:
|
||||
tqdm = None
|
||||
|
||||
try:
|
||||
from proteus import Model, config
|
||||
except ImportError:
|
||||
prog = os.path.basename(sys.argv[0])
|
||||
sys.exit("proteus must be installed to use %s" % prog)
|
||||
|
||||
|
||||
def _progress(iterable, **kwargs):
|
||||
if tqdm:
|
||||
return tqdm(iterable, disable=None, **kwargs)
|
||||
else:
|
||||
return iterable
|
||||
|
||||
|
||||
def clean(code):
|
||||
sys.stderr.write('Cleaning')
|
||||
PostalCode = Model.get('country.postal_code')
|
||||
PostalCode._proxy.delete(
|
||||
[c.id for c in PostalCode.find([('country.code', '=', code)])], {})
|
||||
print('.', file=sys.stderr)
|
||||
|
||||
|
||||
def fetch(code):
|
||||
sys.stderr.write('Fetching')
|
||||
url = 'https://downloads.tryton.org/geonames/%s.zip' % code
|
||||
try:
|
||||
responce = urlopen(url)
|
||||
except HTTPError as e:
|
||||
sys.exit("\nError downloading %s: %s" % (code, e.reason))
|
||||
data = responce.read()
|
||||
with zipfile.ZipFile(BytesIO(data)) as zf:
|
||||
data = zf.read('%s.txt' % code)
|
||||
print('.', file=sys.stderr)
|
||||
return data
|
||||
|
||||
|
||||
def import_(data):
|
||||
PostalCode = Model.get('country.postal_code')
|
||||
Country = Model.get('country.country')
|
||||
Subdivision = Model.get('country.subdivision')
|
||||
print('Importing', file=sys.stderr)
|
||||
|
||||
def get_country(code):
|
||||
country = countries.get(code)
|
||||
if not country:
|
||||
try:
|
||||
country, = Country.find([('code', '=', code)])
|
||||
except ValueError:
|
||||
sys.exit("Error missing country with code %s" % code)
|
||||
countries[code] = country
|
||||
return country
|
||||
countries = {}
|
||||
|
||||
def get_subdivision(country, code):
|
||||
code = '%s-%s' % (country, code)
|
||||
subdivision = subdivisions.get(code)
|
||||
if not subdivision:
|
||||
try:
|
||||
subdivision, = Subdivision.find([('code', '=', code)])
|
||||
except ValueError:
|
||||
return
|
||||
subdivisions[code] = subdivision
|
||||
return subdivision
|
||||
subdivisions = {}
|
||||
|
||||
f = TextIOWrapper(BytesIO(data), encoding='utf-8')
|
||||
codes = []
|
||||
for row in _progress(csv.DictReader(
|
||||
f, fieldnames=_fieldnames, delimiter='\t'),
|
||||
total=data.count(b'\n')):
|
||||
country = get_country(row['country'])
|
||||
for code in ['code1', 'code2', 'code3']:
|
||||
subdivision = get_subdivision(row['country'], row[code])
|
||||
if code == 'code1' or subdivision:
|
||||
codes.append(
|
||||
PostalCode(country=country, subdivision=subdivision,
|
||||
postal_code=row['postal'], city=row['place']))
|
||||
PostalCode.save(codes)
|
||||
|
||||
|
||||
_fieldnames = ['country', 'postal', 'place', 'name1', 'code1',
|
||||
'name2', 'code2', 'name3', 'code3', 'latitude', 'longitude', 'accuracy']
|
||||
|
||||
|
||||
def main(database, codes, config_file=None):
|
||||
config.set_trytond(database, config_file=config_file)
|
||||
do_import(codes)
|
||||
|
||||
|
||||
def do_import(codes):
|
||||
for code in codes:
|
||||
print(code, file=sys.stderr)
|
||||
code = code.upper()
|
||||
clean(code)
|
||||
import_(fetch(code))
|
||||
|
||||
|
||||
def run():
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('-d', '--database', dest='database', required=True)
|
||||
parser.add_argument('-c', '--config', dest='config_file',
|
||||
help='the trytond config file')
|
||||
parser.add_argument('codes', nargs='+')
|
||||
if argcomplete:
|
||||
argcomplete.autocomplete(parser)
|
||||
|
||||
args = parser.parse_args()
|
||||
main(args.database, args.codes, args.config_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
2
modules/country/tests/__init__.py
Normal file
2
modules/country/tests/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
BIN
modules/country/tests/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
modules/country/tests/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
modules/country/tests/__pycache__/test_module.cpython-311.pyc
Normal file
BIN
modules/country/tests/__pycache__/test_module.cpython-311.pyc
Normal file
Binary file not shown.
BIN
modules/country/tests/__pycache__/test_scenario.cpython-311.pyc
Normal file
BIN
modules/country/tests/__pycache__/test_scenario.cpython-311.pyc
Normal file
Binary file not shown.
26
modules/country/tests/scenario_country_import.rst
Normal file
26
modules/country/tests/scenario_country_import.rst
Normal file
@@ -0,0 +1,26 @@
|
||||
==============
|
||||
Country Import
|
||||
==============
|
||||
|
||||
Imports::
|
||||
|
||||
>>> from proteus import Model
|
||||
>>> from trytond.modules.country.scripts import (
|
||||
... import_countries, import_postal_codes)
|
||||
>>> from trytond.tests.tools import activate_modules
|
||||
|
||||
Activate modules::
|
||||
|
||||
>>> config = activate_modules('country')
|
||||
|
||||
Import countries::
|
||||
|
||||
>>> Country = Model.get('country.country')
|
||||
>>> belgium = Country(name="Belgium", code='BE')
|
||||
>>> belgium.save()
|
||||
|
||||
>>> import_countries.do_import()
|
||||
|
||||
Import postal codes::
|
||||
|
||||
>>> import_postal_codes.do_import(['us'])
|
||||
115
modules/country/tests/test_module.py
Normal file
115
modules/country/tests/test_module.py
Normal file
@@ -0,0 +1,115 @@
|
||||
# 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 datetime as dt
|
||||
|
||||
from trytond.pool import Pool
|
||||
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
|
||||
|
||||
|
||||
class CountryTestCase(ModuleTestCase):
|
||||
'Test Country module'
|
||||
module = 'country'
|
||||
|
||||
def create_membership(self, from_date=None, to_date=None):
|
||||
pool = Pool()
|
||||
Country = pool.get('country.country')
|
||||
Organization = pool.get('country.organization')
|
||||
OrganizationMember = pool.get('country.organization.member')
|
||||
|
||||
organization = Organization(name="Organization")
|
||||
organization.save()
|
||||
country = Country(name="Country")
|
||||
country.save()
|
||||
member = OrganizationMember(
|
||||
organization=organization, country=country,
|
||||
from_date=from_date, to_date=to_date)
|
||||
member.save()
|
||||
return organization, country
|
||||
|
||||
@with_transaction()
|
||||
def test_is_member_no_date(self):
|
||||
"Test is member without date"
|
||||
organization, country = self.create_membership()
|
||||
|
||||
self.assertTrue(country.is_member(organization))
|
||||
self.assertTrue(country.is_member(organization, dt.date.min))
|
||||
self.assertTrue(country.is_member(organization, dt.date.max))
|
||||
|
||||
@with_transaction()
|
||||
def test_is_member_with_from_date(self):
|
||||
"Test is member with from date"
|
||||
today = dt.date.today()
|
||||
yesterday = today - dt.timedelta(days=1)
|
||||
tomorrow = today + dt.timedelta(days=1)
|
||||
organization, country = self.create_membership(from_date=today)
|
||||
|
||||
self.assertTrue(country.is_member(organization, today))
|
||||
self.assertFalse(country.is_member(organization, yesterday))
|
||||
self.assertTrue(country.is_member(organization, tomorrow))
|
||||
self.assertFalse(country.is_member(organization, dt.date.min))
|
||||
self.assertTrue(country.is_member(organization, dt.date.max))
|
||||
|
||||
@with_transaction()
|
||||
def test_is_member_with_to_date(self):
|
||||
"Test is member with to date"
|
||||
today = dt.date.today()
|
||||
yesterday = today - dt.timedelta(days=1)
|
||||
tomorrow = today + dt.timedelta(days=1)
|
||||
organization, country = self.create_membership(to_date=today)
|
||||
|
||||
self.assertTrue(country.is_member(organization, today))
|
||||
self.assertTrue(country.is_member(organization, yesterday))
|
||||
self.assertFalse(country.is_member(organization, tomorrow))
|
||||
self.assertTrue(country.is_member(organization, dt.date.min))
|
||||
self.assertFalse(country.is_member(organization, dt.date.max))
|
||||
|
||||
@with_transaction()
|
||||
def test_is_member_with_dates(self):
|
||||
"Test is member with dates"
|
||||
today = dt.date.today()
|
||||
yesterday = today - dt.timedelta(days=1)
|
||||
tomorrow = today + dt.timedelta(days=1)
|
||||
organization, country = self.create_membership(
|
||||
from_date=yesterday, to_date=tomorrow)
|
||||
|
||||
self.assertTrue(country.is_member(organization, today))
|
||||
self.assertTrue(country.is_member(organization, yesterday))
|
||||
self.assertFalse(country.is_member(organization, dt.date.min))
|
||||
self.assertFalse(country.is_member(organization, dt.date.max))
|
||||
|
||||
@with_transaction()
|
||||
def test_subdivision_code_search(self):
|
||||
"Test search on subdivision code"
|
||||
pool = Pool()
|
||||
Country = pool.get('country.country')
|
||||
Subdivision = pool.get('country.subdivision')
|
||||
|
||||
fr, = Country.create([{'name': 'France'}])
|
||||
paris, nord = Subdivision.create([{
|
||||
'name': 'Paris',
|
||||
'code': 'FR-75',
|
||||
'country': fr,
|
||||
}, {
|
||||
'name': 'Nord',
|
||||
'code': 'FR-59',
|
||||
'country': fr,
|
||||
}])
|
||||
|
||||
for domain, result in [
|
||||
([('code', '=', 'FR-59')], [nord]),
|
||||
([('code', '!=', 'FR-59')], [paris]),
|
||||
([('code', '=', '59')], []),
|
||||
([('code', '!=', '59')], [nord, paris]),
|
||||
([('code', 'like', '59%')], [nord]),
|
||||
([('code', 'not like', '59%')], [paris]),
|
||||
([('code', 'ilike', '59%')], [nord]),
|
||||
([('code', 'not like', '59%')], [paris]),
|
||||
]:
|
||||
with self.subTest(domain=domain):
|
||||
self.assertEqual(Subdivision.search(
|
||||
domain, order=[('name', 'ASC')]),
|
||||
result)
|
||||
|
||||
|
||||
del ModuleTestCase
|
||||
10
modules/country/tests/test_scenario.py
Normal file
10
modules/country/tests/test_scenario.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# 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.tests.test_tryton import TEST_NETWORK, load_doc_tests
|
||||
|
||||
|
||||
def load_tests(*args, **kwargs):
|
||||
if not TEST_NETWORK:
|
||||
kwargs.setdefault('skips', set()).add('scenario_country_import.rst')
|
||||
return load_doc_tests(__name__, __file__, *args, **kwargs)
|
||||
18
modules/country/tryton.cfg
Normal file
18
modules/country/tryton.cfg
Normal file
@@ -0,0 +1,18 @@
|
||||
[tryton]
|
||||
version=7.8.0
|
||||
depends:
|
||||
ir
|
||||
res
|
||||
xml:
|
||||
country.xml
|
||||
organization.xml
|
||||
region.xml
|
||||
|
||||
[register]
|
||||
model:
|
||||
country.Organization
|
||||
country.OrganizationMember
|
||||
country.Region
|
||||
country.Country
|
||||
country.Subdivision
|
||||
country.PostalCode
|
||||
21
modules/country/view/country_form.xml
Normal file
21
modules/country/view/country_form.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?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. -->
|
||||
<form col="6">
|
||||
<label name="name"/>
|
||||
<field name="name"/>
|
||||
<label name="region"/>
|
||||
<field name="region"/>
|
||||
<label name="active"/>
|
||||
<field name="active"/>
|
||||
|
||||
<label name="code"/>
|
||||
<field name="code"/>
|
||||
<label name="code3"/>
|
||||
<field name="code3"/>
|
||||
<label name="code_numeric"/>
|
||||
<field name="code_numeric"/>
|
||||
<field name="subdivisions" colspan="6"/>
|
||||
|
||||
<field name="members" colspan="6"/>
|
||||
</form>
|
||||
12
modules/country/view/country_tree.xml
Normal file
12
modules/country/view/country_tree.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?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. -->
|
||||
<tree>
|
||||
<field name="name" expand="2">
|
||||
<prefix name="flag"/>
|
||||
</field>
|
||||
<field name="code" optional="1"/>
|
||||
<field name="code3" optional="1"/>
|
||||
<field name="code_numeric" optional="1"/>
|
||||
<field name="region" expand="1" optional="1"/>
|
||||
</tree>
|
||||
11
modules/country/view/organization_form.xml
Normal file
11
modules/country/view/organization_form.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?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. -->
|
||||
<form>
|
||||
<label name="name"/>
|
||||
<field name="name"/>
|
||||
<label name="code"/>
|
||||
<field name="code"/>
|
||||
|
||||
<field name="members" colspan="4"/>
|
||||
</form>
|
||||
7
modules/country/view/organization_list.xml
Normal file
7
modules/country/view/organization_list.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?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. -->
|
||||
<tree>
|
||||
<field name="name" expand="2"/>
|
||||
<field name="code" optional="0"/>
|
||||
</tree>
|
||||
14
modules/country/view/organization_member_form.xml
Normal file
14
modules/country/view/organization_member_form.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?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. -->
|
||||
<form>
|
||||
<label name="country"/>
|
||||
<field name="country"/>
|
||||
<label name="organization"/>
|
||||
<field name="organization"/>
|
||||
|
||||
<label name="from_date"/>
|
||||
<field name="from_date"/>
|
||||
<label name="to_date"/>
|
||||
<field name="to_date"/>
|
||||
</form>
|
||||
9
modules/country/view/organization_member_list.xml
Normal file
9
modules/country/view/organization_member_list.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?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. -->
|
||||
<tree>
|
||||
<field name="country" expand="2"/>
|
||||
<field name="organization" expand="2"/>
|
||||
<field name="from_date" optional="0"/>
|
||||
<field name="to_date" optional="0"/>
|
||||
</tree>
|
||||
13
modules/country/view/postal_code_form.xml
Normal file
13
modules/country/view/postal_code_form.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?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. -->
|
||||
<form>
|
||||
<label name="country"/>
|
||||
<field name="country"/>
|
||||
<label name="subdivision"/>
|
||||
<field name="subdivision"/>
|
||||
<label name="postal_code"/>
|
||||
<field name="postal_code"/>
|
||||
<label name="city"/>
|
||||
<field name="city"/>
|
||||
</form>
|
||||
9
modules/country/view/postal_code_list.xml
Normal file
9
modules/country/view/postal_code_list.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?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. -->
|
||||
<tree>
|
||||
<field name="country" expand="1"/>
|
||||
<field name="subdivision" expand="1"/>
|
||||
<field name="postal_code" expand="1"/>
|
||||
<field name="city" expand="1"/>
|
||||
</tree>
|
||||
16
modules/country/view/region_form.xml
Normal file
16
modules/country/view/region_form.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?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. -->
|
||||
<form>
|
||||
<label name="name"/>
|
||||
<field name="name"/>
|
||||
<label name="code_numeric"/>
|
||||
<field name="code_numeric"/>
|
||||
|
||||
<label name="parent"/>
|
||||
<field name="parent"/>
|
||||
|
||||
<field name="subregions" colspan="4"/>
|
||||
|
||||
<field name="countries" colspan="4"/>
|
||||
</form>
|
||||
7
modules/country/view/region_list.xml
Normal file
7
modules/country/view/region_list.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?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. -->
|
||||
<tree>
|
||||
<field name="name" expand="1"/>
|
||||
<field name="code_numeric" optional="1"/>
|
||||
</tree>
|
||||
7
modules/country/view/region_tree.xml
Normal file
7
modules/country/view/region_tree.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?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. -->
|
||||
<tree keyword_open="1">
|
||||
<field name="name" expand="1"/>
|
||||
<field name="code_numeric" optional="1"/>
|
||||
</tree>
|
||||
18
modules/country/view/subdivision_form.xml
Normal file
18
modules/country/view/subdivision_form.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?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. -->
|
||||
<form col="6">
|
||||
<label name="country"/>
|
||||
<field name="country"/>
|
||||
<newline/>
|
||||
<label name="name"/>
|
||||
<field name="name"/>
|
||||
<label name="code"/>
|
||||
<field name="code"/>
|
||||
<label name="active"/>
|
||||
<field name="active"/>
|
||||
<label name="type"/>
|
||||
<field name="type"/>
|
||||
<label name="parent"/>
|
||||
<field name="parent"/>
|
||||
</form>
|
||||
8
modules/country/view/subdivision_tree.xml
Normal file
8
modules/country/view/subdivision_tree.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?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. -->
|
||||
<tree>
|
||||
<field name="name" expand="1"/>
|
||||
<field name="code"/>
|
||||
<field name="type"/>
|
||||
</tree>
|
||||
Reference in New Issue
Block a user