diff --git a/modules/country/CHANGELOG b/modules/country/CHANGELOG index dc8eea2694..3a1d0f0bff 100644 --- a/modules/country/CHANGELOG +++ b/modules/country/CHANGELOG @@ -1,3 +1,4 @@ +* Allow searching on subdivision shorter code Version 7.4.0 - 2024-11-04 -------------------------- diff --git a/modules/country/country.py b/modules/country/country.py index 4dcc819728..d62562063b 100644 --- a/modules/country/country.py +++ b/modules/country/country.py @@ -1,9 +1,11 @@ # 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 import backend from trytond.model import DeactivableMixin, ModelSQL, ModelView, fields, tree @@ -458,6 +460,26 @@ class Subdivision(DeactivableMixin, ModelSQL, ModelView): ('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 create(cls, vlist): vlist = [x.copy() for x in vlist] diff --git a/modules/country/tests/test_module.py b/modules/country/tests/test_module.py index 8a02c3e6db..7491567078 100644 --- a/modules/country/tests/test_module.py +++ b/modules/country/tests/test_module.py @@ -78,5 +78,38 @@ class CountryTestCase(ModuleTestCase): 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