From 5ed7f4e1d1978d4fb336ac4454a1d8994d5ef090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 15 Sep 2022 21:45:37 +0200 Subject: [PATCH] Add country organizations issue11689 review417911003 --- CHANGELOG | 1 + __init__.py | 2 + country.py | 121 +++++++++++- country.xml | 60 ++++++ doc/design.rst | 18 ++ organization.xml | 101 ++++++++++ scripts/import_countries.py | 307 +++++++++++++++++++++++++++++- setup.py | 2 +- tests/test_module.py | 72 ++++++- tryton.cfg | 1 + view/country_form.xml | 2 + view/organization_form.xml | 11 ++ view/organization_list.xml | 7 + view/organization_member_form.xml | 14 ++ view/organization_member_list.xml | 9 + 15 files changed, 724 insertions(+), 4 deletions(-) create mode 100644 organization.xml create mode 100644 view/organization_form.xml create mode 100644 view/organization_list.xml create mode 100644 view/organization_member_form.xml create mode 100644 view/organization_member_list.xml diff --git a/CHANGELOG b/CHANGELOG index 9eed3a2ae3..2b3f684f11 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Add country organizations * Add UN M49 regions * Add flag symbol for country and subdivision diff --git a/__init__.py b/__init__.py index b229037c5f..dcc3549d5f 100644 --- a/__init__.py +++ b/__init__.py @@ -8,6 +8,8 @@ def register(): # Prevent to import backend when importing scripts from . import country Pool.register( + country.Organization, + country.OrganizationMember, country.Region, country.Country, country.Subdivision, diff --git a/country.py b/country.py index a53df52a01..51805c1239 100644 --- a/country.py +++ b/country.py @@ -1,13 +1,109 @@ # 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 sql import Literal +from sql.conditionals import Coalesce + from trytond import backend from trytond.model import DeactivableMixin, ModelSQL, ModelView, fields, tree from trytond.pool import Pool -from trytond.pyson import Eval +from trytond.pyson import Eval, If from trytond.tools import lstrip_wildcard from trytond.transaction import Transaction +class Organization(ModelSQL, ModelView): + "Organization" + __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): + "Organization Member" + __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): "Region" __name__ = 'country.region' @@ -60,6 +156,14 @@ class Country(DeactivableMixin, ModelSQL, ModelView): '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): @@ -115,6 +219,21 @@ class Country(DeactivableMixin, ModelSQL, ModelView): ('code_numeric', clause[1], code_value) + tuple(clause[3:]), ] + 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 create(cls, vlist): vlist = [x.copy() for x in vlist] diff --git a/country.xml b/country.xml index f848c2ebde..97b5906142 100644 --- a/country.xml +++ b/country.xml @@ -20,6 +20,66 @@ this repository contains the full copyright notices and license terms. --> + + country.organization + form + organization_form + + + + country.organization + tree + organization_list + + + + Organizations + country.organization + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + country.organization.member + form + organization_member_form + + + + country.organization.member + tree + organization_member_list + + country.region form diff --git a/doc/design.rst b/doc/design.rst index 609a4f23c7..1d3c3ed9d6 100644 --- a/doc/design.rst +++ b/doc/design.rst @@ -4,6 +4,24 @@ Design The *Country Module* introduces the following concepts: +.. _model-country.organization: + +Organization +============ + +The *Organization* represents an international organization of `Countries +`. + +.. seealso:: + + Organizations can be found under the main menu entry: + + |Administration --> Countries --> Organizations|__ + + .. |Administration --> Countries --> Organizations| replace:: :menuselection:`Administration --> Countries --> Organizations` + __ https://demo.tryton.org/model/country.organization + + .. _model-country.region: Region diff --git a/organization.xml b/organization.xml new file mode 100644 index 0000000000..f74f7bb827 --- /dev/null +++ b/organization.xml @@ -0,0 +1,101 @@ + + + + + + European Union + EU + + + + Benelux Union + Benelux + + + + North American Free Trade Agreement + NAFTA + + + + Southern Common Market + Mercosur + + + + Andean Community + CAN + + + + Caribbean Community + CARICOM + + + + Asia-Pacific Economic Cooperation + APEC + + + + Association of Southeast Asian Nations + ASEAN + + + + South Asian Free Trade Area + SAFTA + + + + Cooperation Council for the Arab States of the Gulf + GCC + + + + Economic and Monetary Community of Central Africa + CEMAC + + + + Economic Community of Central African States + ECCAS + + + + Economic Community of West African States + ECOWAS + + + + Community of Sahel–Saharan States + CEN-SAD + + + + Common Market for Eastern and Southern Africa + COMESA + + + + East African Community + EAC + + + + Intergovernmental Authority on Development + IGAD + + + + Southern African Development Community + SADC + + + + Arab Maghreb Union + AMU + + + diff --git a/scripts/import_countries.py b/scripts/import_countries.py index 6d33eac824..463d055e1e 100755 --- a/scripts/import_countries.py +++ b/scripts/import_countries.py @@ -2,6 +2,8 @@ # 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 @@ -25,6 +27,286 @@ 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'], @@ -109,10 +391,18 @@ def get_countries(): 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([])} @@ -122,11 +412,26 @@ def update_countries(countries): if code in countries: record = countries[code] else: - record = Country(code=code) + 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) diff --git a/setup.py b/setup.py index e51364c83d..b0d5fe4e8c 100755 --- a/setup.py +++ b/setup.py @@ -61,7 +61,7 @@ else: if local_version: version += '+' + '.'.join(local_version) -requires = [] +requires = ['python-sql'] for dep in info.get('depends', []): if not re.match(r'(ir|res)(\W|$)', dep): requires.append(get_require_version('trytond_%s' % dep)) diff --git a/tests/test_module.py b/tests/test_module.py index 66e772ea28..8a02c3e6db 100644 --- a/tests/test_module.py +++ b/tests/test_module.py @@ -1,12 +1,82 @@ # 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 ModuleTestCase +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)) + del ModuleTestCase diff --git a/tryton.cfg b/tryton.cfg index 65b4cf72da..c2a9f0cc12 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -5,4 +5,5 @@ depends: res xml: country.xml + organization.xml region.xml diff --git a/view/country_form.xml b/view/country_form.xml index 7042e8479b..c670232a96 100644 --- a/view/country_form.xml +++ b/view/country_form.xml @@ -16,4 +16,6 @@ this repository contains the full copyright notices and license terms. -->