diff --git a/trytond/trytond/model/fields/one2many.py b/trytond/trytond/model/fields/one2many.py index 72e7425e3f..aa4cb055a9 100644 --- a/trytond/trytond/model/fields/one2many.py +++ b/trytond/trytond/model/fields/one2many.py @@ -316,8 +316,10 @@ class One2Many(Field): where &= history_where if origin_where: where &= origin_where - if self.filter: - query = Target.search(self.filter, order=[], query=True) + if self.filter or hasattr(Target, 'active'): + # Use an empty filter to apply the active test + filter_ = self.filter if self.filter else [] + query = Target.search(filter_, order=[], query=True) where &= target.id.in_(query) query = target.select(origin, where=where) expression = ~table.id.in_(query) diff --git a/trytond/trytond/tests/field_many2many.py b/trytond/trytond/tests/field_many2many.py index d70c793839..815bbe7134 100644 --- a/trytond/trytond/tests/field_many2many.py +++ b/trytond/trytond/tests/field_many2many.py @@ -1,7 +1,7 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. -from trytond.model import ModelSQL, fields +from trytond.model import DeactivableMixin, ModelSQL, fields from trytond.pool import Pool from trytond.transaction import Transaction @@ -180,6 +180,51 @@ class Many2ManyContextTarget(ModelSQL): return context.get('test') +class Many2ManyActive(ModelSQL): + "Many2Many Active" + __name__ = 'test.many2many_active' + targets = fields.Many2Many( + 'test.many2many_active.relation', 'origin', 'target', 'Targets') + + +class Many2ManyTargetActive(DeactivableMixin, ModelSQL): + "Many2Many Target Active" + __name__ = 'test.many2many_active.target' + name = fields.Char('Name') + + +class Many2ManyRelationActive(ModelSQL): + "Many2Many Relation Active" + __name__ = 'test.many2many_active.relation' + origin = fields.Many2One('test.many2many_active', 'Origin') + target = fields.Many2One('test.many2many_active.target', 'Target') + + +class Many2ManyReferenceActive(ModelSQL): + "Many2Many Reference Active" + __name__ = 'test.many2many_reference.active' + targets = fields.Many2Many( + 'test.many2many_reference.active.relation', 'origin', 'target', + "Targets") + + +class Many2ManyReferenceActiveTarget(DeactivableMixin, ModelSQL): + "Many2Many Reference Active Target" + __name__ = 'test.many2many_reference.active.target' + name = fields.Char('Name') + + +class Many2ManyReferenceActiveRelation(ModelSQL): + "Many2Many Reference Active Relation" + __name__ = 'test.many2many_reference.active.relation' + origin = fields.Reference('Origin', [ + (None, ''), + ('test.many2many_reference.active', 'Many2Many Reference'), + ]) + target = fields.Many2One('test.many2many_reference.active.target', + 'Reference Target') + + def register(module): Pool.register( Many2Many, @@ -205,4 +250,10 @@ def register(module): Many2ManyContext, Many2ManyContextTarget, Many2ManyContextRelation, + Many2ManyActive, + Many2ManyTargetActive, + Many2ManyRelationActive, + Many2ManyReferenceActive, + Many2ManyReferenceActiveRelation, + Many2ManyReferenceActiveTarget, module=module, type_='model') diff --git a/trytond/trytond/tests/field_one2many.py b/trytond/trytond/tests/field_one2many.py index a1848cf8a7..9fe9d9552d 100644 --- a/trytond/trytond/tests/field_one2many.py +++ b/trytond/trytond/tests/field_one2many.py @@ -1,7 +1,7 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. -from trytond.model import ModelSQL, fields +from trytond.model import DeactivableMixin, ModelSQL, fields from trytond.pool import Pool from trytond.pyson import Eval from trytond.transaction import Transaction @@ -130,6 +130,37 @@ class One2ManyContextTarget(ModelSQL): return context.get('test') +class One2ManyActive(ModelSQL): + "One2Many Active" + __name__ = 'test.one2many.active' + targets = fields.One2Many( + 'test.one2many.active_target', 'origin', "Targets") + + +class One2ManyActiveTarget(DeactivableMixin, ModelSQL): + "One2Many Active Target" + __name__ = 'test.one2many.active_target' + name = fields.Char('Name') + origin = fields.Many2One('test.one2many.active', "Origin") + + +class One2ManyActiveReference(ModelSQL): + "One2Many Active Reference" + __name__ = 'test.one2many_reference.active' + targets = fields.One2Many( + 'test.one2many_reference.active_target', 'origin', "Targets") + + +class One2ManyActiveReferenceTarget(DeactivableMixin, ModelSQL): + "One2Many Active Reference Target" + __name__ = 'test.one2many_reference.active_target' + name = fields.Char('Name') + origin = fields.Reference('Origin', [ + (None, ''), + ('test.one2many_reference.active', 'One2Many Reference'), + ]) + + def register(module): Pool.register( One2Many, @@ -148,4 +179,8 @@ def register(module): One2ManyFilterDomainTarget, One2ManyContext, One2ManyContextTarget, + One2ManyActive, + One2ManyActiveTarget, + One2ManyActiveReference, + One2ManyActiveReferenceTarget, module=module, type_='model') diff --git a/trytond/trytond/tests/test_field_many2many.py b/trytond/trytond/tests/test_field_many2many.py index 0844e3b86a..50af506725 100644 --- a/trytond/trytond/tests/test_field_many2many.py +++ b/trytond/trytond/tests/test_field_many2many.py @@ -100,6 +100,48 @@ class CommonTestCaseMixin: self.assertListEqual(many2manys, [many2many1]) + @with_transaction() + def test_search_equals_none_inactive(self): + "Test search many2many equals None when the target is inactive" + Many2Many = self.Many2ManyActive() + + many2many1, many2many2, many2many3 = Many2Many.create([{ + 'targets': [('create', [{'name': "Target"}])], + }, { + 'targets': [ + ('create', [{'name': "Target", 'active': False}]) + ], + }, { + 'targets': None, + }]) + + many2manys = Many2Many.search([ + ('targets', '=', None), + ]) + + self.assertListEqual(many2manys, [many2many3]) + + @with_transaction() + def test_search_non_equals_none_inactive(self): + "Test search many2many equals non None when the target is inactive" + Many2Many = self.Many2ManyActive() + + many2many1, many2many2, many2many3 = Many2Many.create([{ + 'targets': [('create', [{'name': "Target"}])], + }, { + 'targets': [ + ('create', [{'name': "Target", 'active': False}]) + ], + }, { + 'targets': None, + }]) + + many2manys = Many2Many.search([ + ('targets', '!=', None), + ]) + + self.assertListEqual(many2manys, [many2many1, many2many2]) + @with_transaction() def test_search_non_equals_no_link(self): "Test search many2many non equals without link" @@ -387,6 +429,9 @@ class FieldMany2ManyTestCase(unittest.TestCase, CommonTestCaseMixin): def Many2ManyTarget(self): return Pool().get('test.many2many.target') + def Many2ManyActive(self): + return Pool().get('test.many2many_active') + @with_transaction() def test_create_required_with_value(self): "Test create many2many required with value" @@ -740,6 +785,9 @@ class FieldMany2ManyReferenceTestCase(unittest.TestCase, CommonTestCaseMixin): def Many2ManyTarget(self): return Pool().get('test.many2many_reference.target') + def Many2ManyActive(self): + return Pool().get('test.many2many_reference.active') + def suite(): suite_ = unittest.TestSuite() diff --git a/trytond/trytond/tests/test_field_one2many.py b/trytond/trytond/tests/test_field_one2many.py index 4ec9cafdf7..31f3b7f097 100644 --- a/trytond/trytond/tests/test_field_one2many.py +++ b/trytond/trytond/tests/test_field_one2many.py @@ -146,6 +146,46 @@ class CommonTestCaseMixin: self.assertListEqual(one2manys, [one2many2]) + @with_transaction() + def test_search_equals_none_inactive(self): + "Test search one2many equals None when the target is inactive" + One2Many = self.One2ManyActive() + one2many1, one2many2, one2many3 = One2Many.create([{ + 'targets': [('create', [{'name': "Target1"}])], + }, { + 'targets': [ + ('create', [{'name': "Target2", 'active': False}]), + ], + }, { + 'targets': None, + }]) + + one2manys = One2Many.search([ + ('targets', '=', None), + ]) + + self.assertEqual(one2manys, [one2many2, one2many3]) + + @with_transaction() + def test_search_not_equals_none_inactive(self): + "Test search one2many not equals None when the target is inactive" + One2Many = self.One2ManyActive() + one2many1, one2many2, one2many3 = One2Many.create([{ + 'targets': [('create', [{'name': "Target1"}])], + }, { + 'targets': [ + ('create', [{'name': "Target2", 'active': False}]), + ], + }, { + 'targets': None, + }]) + + one2manys = One2Many.search([ + ('targets', '!=', None), + ]) + + self.assertEqual(one2manys, [one2many1]) + @with_transaction() def test_search_non_equals_none(self): "Test search one2many non equals None" @@ -446,6 +486,9 @@ class FieldOne2ManyTestCase(unittest.TestCase, CommonTestCaseMixin): def One2ManyTarget(self): return Pool().get('test.one2many.target') + def One2ManyActive(self): + return Pool().get('test.one2many.active') + @with_transaction() def test_create_required_with_value(self): "Test create one2many required with value" @@ -661,6 +704,9 @@ class FieldOne2ManyReferenceTestCase(unittest.TestCase, CommonTestCaseMixin): def One2ManyTarget(self): return Pool().get('test.one2many_reference.target') + def One2ManyActive(self): + return Pool().get('test.one2many_reference.active') + def suite(): suite_ = unittest.TestSuite()