diff --git a/CHANGELOG b/CHANGELOG
index d4d173e129..27555885a2 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,5 @@
+* Enforce companies rule
+* Add company filter
* Remove tree structure from company
* Add test on context of company multivalue target fields
* Use report header for CompanyReport
diff --git a/ir.py b/ir.py
index 4d4a9e52b1..d133ddf140 100644
--- a/ir.py
+++ b/ir.py
@@ -56,14 +56,19 @@ class Rule(metaclass=PoolMeta):
def __setup__(cls):
super().__setup__()
cls.domain.help += '\n- "employee" from the current user'
+ cls.domain.help += '\n- "companies" from the current user'
@classmethod
def _get_cache_key(cls):
key = super(Rule, cls)._get_cache_key()
# XXX Use company from context instead of browse to prevent infinite
# loop, but the cache is cleared when User is written.
- return key + (Transaction().context.get('company'),
- Transaction().context.get('employee'))
+ context = Transaction().context
+ return key + (
+ context.get('company'),
+ context.get('employee'),
+ context.get('company_filter'),
+ )
@classmethod
def _get_context(cls):
@@ -79,6 +84,15 @@ class Rule(metaclass=PoolMeta):
_check_access=False, _datetime=None):
context['employee'] = EvalEnvironment(
Employee(user.employee.id), Employee)
+ if user.company_filter == 'one':
+ context['companies'] = [user.company.id] if user.company else []
+ context['employees'] = [user.employee.id] if user.employee else []
+ elif user.company_filter == 'all':
+ context['companies'] = [c.id for c in user.companies]
+ context['employees'] = [e.id for e in user.employees]
+ else:
+ context['companies'] = []
+ context['employees'] = []
return context
diff --git a/ir.xml b/ir.xml
index de5ef43c60..7c42b59f73 100644
--- a/ir.xml
+++ b/ir.xml
@@ -15,36 +15,36 @@ this repository contains the full copyright notices and license terms. -->
sequence_tree
-
- User in company
+
+ User in companies
-
+
-
+
-
+
-
+
-
- User in company
+
+ User in companies
-
+
-
+
-
+
-
+
diff --git a/res.py b/res.py
index 6c8d574c8c..8d5f099cab 100644
--- a/res.py
+++ b/res.py
@@ -55,12 +55,18 @@ class User(metaclass=PoolMeta):
],
depends=['company', 'employees'],
help="Select the employee to make the user behave as such.")
+ company_filter = fields.Selection([
+ ('one', "Current"),
+ ('all', "All"),
+ ], "Company Filter",
+ help="Define records of which companies are shown.")
@classmethod
def __setup__(cls):
super(User, cls).__setup__()
cls._context_fields.insert(0, 'company')
cls._context_fields.insert(0, 'employee')
+ cls._context_fields.insert(0, 'company_filter')
@classmethod
def __register__(cls, module):
@@ -99,6 +105,10 @@ class User(metaclass=PoolMeta):
def default_company(cls):
return Transaction().context.get('company')
+ @classmethod
+ def default_company_filter(cls):
+ return 'one'
+
def get_status_bar(self, name):
def same_company(record):
return record.company == self.company
diff --git a/tests/__init__.py b/tests/__init__.py
index 531f4832ed..7c5d418f05 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -4,12 +4,12 @@
try:
from trytond.modules.company.tests.test_company import (
suite, create_company, set_company, create_employee,
- PartyCompanyCheckEraseMixin, CompanyMultiValueTestMixin)
+ PartyCompanyCheckEraseMixin, CompanyTestMixin)
except ImportError:
from .test_company import (
suite, create_company, set_company, create_employee,
- PartyCompanyCheckEraseMixin, CompanyMultiValueTestMixin)
+ PartyCompanyCheckEraseMixin, CompanyTestMixin)
__all__ = [
'suite', 'create_company', 'set_company', 'create_employee',
- 'PartyCompanyCheckEraseMixin', 'CompanyMultiValueTestMixin']
+ 'PartyCompanyCheckEraseMixin', 'CompanyTestMixin']
diff --git a/tests/test_company.py b/tests/test_company.py
index b743f50d66..939cd340f2 100644
--- a/tests/test_company.py
+++ b/tests/test_company.py
@@ -1,12 +1,15 @@
# 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 unittest
+from collections import defaultdict
from contextlib import contextmanager
import trytond.tests.test_tryton
+from trytond.model import ModelView, ModelStorage
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
from trytond.transaction import Transaction
from trytond.pool import Pool, isregisteredby
+from trytond.pyson import Eval, PYSONEncoder
from trytond.modules.currency.tests import create_currency, add_currency_rate
from trytond.modules.party.tests import PartyCheckEraseMixin
@@ -65,7 +68,7 @@ class PartyCompanyCheckEraseMixin(PartyCheckEraseMixin):
return super().setup_check_erase_party()
-class CompanyMultiValueTestMixin:
+class CompanyTestMixin:
@with_transaction()
def test_company_multivalue_context(self):
@@ -97,10 +100,49 @@ class CompanyMultiValueTestMixin:
'in "%s"."%s" context' % (
company, mname, fname))
+ @with_transaction()
+ def test_company_rule(self):
+ "Test missing company rule"
+ pool = Pool()
+ Rule = pool.get('ir.rule')
+ Company = pool.get('company.company')
+ Employee = pool.get('company.employee')
+ User = pool.get('res.user')
+
+ to_check = defaultdict(set)
+ for mname, model in pool.iterobject():
+ if (not isregisteredby(model, self.module)
+ or model.__access__
+ or not (issubclass(model, ModelView)
+ and issubclass(model, ModelStorage))
+ or issubclass(model, (Company, Employee, User))):
+ continue
+ for fname, field in model._fields.items():
+ if (field._type == 'many2one'
+ and issubclass(field.get_target(), Company)):
+ to_check[fname].add(mname)
+
+ for fname, models in to_check.items():
+ rules = Rule.search([
+ ('rule_group', 'where', [
+ ('model.model', 'in', list(models)),
+ ('global_p', '=', True),
+ ('perm_read', '=', True),
+ ]),
+ ('domain', '=', PYSONEncoder(sort_keys=True).encode(
+ [(fname, 'in', Eval('companies', []))])),
+ ])
+ with_rules = {r.rule_group.model.model for r in rules}
+ self.assertGreaterEqual(with_rules, models,
+ msg='Models "%(models)s" are missing a global rule '
+ 'for field "%(field)s"' % {
+ 'models': ', '.join(models - with_rules),
+ 'field': fname,
+ })
+
class CompanyTestCase(
- PartyCompanyCheckEraseMixin, CompanyMultiValueTestMixin,
- ModuleTestCase):
+ PartyCompanyCheckEraseMixin, CompanyTestMixin, ModuleTestCase):
'Test Company module'
module = 'company'
diff --git a/view/user_form.xml b/view/user_form.xml
index 6787872e73..f9da7f802d 100644
--- a/view/user_form.xml
+++ b/view/user_form.xml
@@ -6,6 +6,9 @@ this repository contains the full copyright notices and license terms. -->
position="before">
+
+
+
diff --git a/view/user_form_preferences.xml b/view/user_form_preferences.xml
index f53ebd7f2f..ffa1553e5b 100644
--- a/view/user_form_preferences.xml
+++ b/view/user_form_preferences.xml
@@ -5,7 +5,11 @@ this repository contains the full copyright notices and license terms. -->
-
+
+
+
+
+