changeset bba2953e5260 in modules/company:default
details: https://hg.tryton.org/modules/company?cmd=changeset&node=bba2953e5260
description:
Check rule only if _check_access is set and enforce companies rule
issue4080
review343891009
diffstat:
CHANGELOG | 2 +
ir.py | 18 ++++++++++++++-
ir.xml | 28 ++++++++++++------------
res.py | 10 ++++++++
tests/__init__.py | 6 ++--
tests/test_company.py | 48 +++++++++++++++++++++++++++++++++++++++--
view/user_form.xml | 3 ++
view/user_form_preferences.xml | 6 ++++-
8 files changed, 98 insertions(+), 23 deletions(-)
diffs (265 lines):
diff -r 6257a7495a11 -r bba2953e5260 CHANGELOG
--- a/CHANGELOG Wed Mar 24 13:48:25 2021 +0100
+++ b/CHANGELOG Sat Apr 10 23:46:23 2021 +0200
@@ -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 -r 6257a7495a11 -r bba2953e5260 ir.py
--- a/ir.py Wed Mar 24 13:48:25 2021 +0100
+++ b/ir.py Sat Apr 10 23:46:23 2021 +0200
@@ -56,14 +56,19 @@
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 @@
_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 -r 6257a7495a11 -r bba2953e5260 ir.xml
--- a/ir.xml Wed Mar 24 13:48:25 2021 +0100
+++ b/ir.xml Sat Apr 10 23:46:23 2021 +0200
@@ -15,36 +15,36 @@
<field name="name">sequence_tree</field>
</record>
- <record model="ir.rule.group" id="rule_group_sequence">
- <field name="name">User in company</field>
+ <record model="ir.rule.group" id="rule_group_sequence_companies">
+ <field name="name">User in companies</field>
<field name="model" search="[('model', '=', 'ir.sequence')]"/>
<field name="global_p" eval="True"/>
</record>
- <record model="ir.rule" id="rule_sequence1">
+ <record model="ir.rule" id="rule_sequence_companies1">
<field name="domain"
- eval="[('company', '=', Eval('user', {}).get('company',
None))]"
+ eval="[('company', 'in', Eval('companies', []))]"
pyson="1"/>
- <field name="rule_group" ref="rule_group_sequence"/>
+ <field name="rule_group" ref="rule_group_sequence_companies"/>
</record>
- <record model="ir.rule" id="rule_sequence2">
+ <record model="ir.rule" id="rule_sequence_comapnies2">
<field name="domain" eval="[('company', '=', None)]" pyson="1"/>
- <field name="rule_group" ref="rule_group_sequence"/>
+ <field name="rule_group" ref="rule_group_sequence_companies"/>
</record>
- <record model="ir.rule.group" id="rule_group_sequence_strict">
- <field name="name">User in company</field>
+ <record model="ir.rule.group"
id="rule_group_sequence_strict_companies">
+ <field name="name">User in companies</field>
<field name="model" search="[('model', '=',
'ir.sequence.strict')]"/>
<field name="global_p" eval="True"/>
</record>
- <record model="ir.rule" id="rule_sequence_strict1">
+ <record model="ir.rule" id="rule_sequence_strict_companies1">
<field name="domain"
- eval="[('company', '=', Eval('user', {}).get('company',
None))]"
+ eval="[('company', 'in', Eval('companies', []))]"
pyson="1"/>
- <field name="rule_group" ref="rule_group_sequence_strict"/>
+ <field name="rule_group"
ref="rule_group_sequence_strict_companies"/>
</record>
- <record model="ir.rule" id="rule_sequence_strict2">
+ <record model="ir.rule" id="rule_sequence_strict_companies2">
<field name="domain" eval="[('company', '=', None)]" pyson="1"/>
- <field name="rule_group" ref="rule_group_sequence_strict"/>
+ <field name="rule_group"
ref="rule_group_sequence_strict_companies"/>
</record>
<record model="ir.ui.view" id="cron_view_form">
diff -r 6257a7495a11 -r bba2953e5260 res.py
--- a/res.py Wed Mar 24 13:48:25 2021 +0100
+++ b/res.py Sat Apr 10 23:46:23 2021 +0200
@@ -55,12 +55,18 @@
],
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 @@
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 -r 6257a7495a11 -r bba2953e5260 tests/__init__.py
--- a/tests/__init__.py Wed Mar 24 13:48:25 2021 +0100
+++ b/tests/__init__.py Sat Apr 10 23:46:23 2021 +0200
@@ -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 -r 6257a7495a11 -r bba2953e5260 tests/test_company.py
--- a/tests/test_company.py Wed Mar 24 13:48:25 2021 +0100
+++ b/tests/test_company.py Sat Apr 10 23:46:23 2021 +0200
@@ -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 @@
return super().setup_check_erase_party()
-class CompanyMultiValueTestMixin:
+class CompanyTestMixin:
@with_transaction()
def test_company_multivalue_context(self):
@@ -97,10 +100,49 @@
'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 -r 6257a7495a11 -r bba2953e5260 view/user_form.xml
--- a/view/user_form.xml Wed Mar 24 13:48:25 2021 +0100
+++ b/view/user_form.xml Sat Apr 10 23:46:23 2021 +0200
@@ -6,6 +6,9 @@
position="before">
<label name="company"/>
<field name="company" widget="selection"/>
+ <label name="company_filter"/>
+ <field name="company_filter"/>
+
<label name="employee"/>
<field name="employee" widget="selection"/>
<field name="companies" colspan="2"/>
diff -r 6257a7495a11 -r bba2953e5260 view/user_form_preferences.xml
--- a/view/user_form_preferences.xml Wed Mar 24 13:48:25 2021 +0100
+++ b/view/user_form_preferences.xml Sat Apr 10 23:46:23 2021 +0200
@@ -5,7 +5,11 @@
<xpath expr="/form/notebook/page/separator[@name='signature']"
position="before">
<label name="company"/>
- <field name="company" widget="selection"/>
+ <group id="company" col="-1">
+ <field name="company" widget="selection"/>
+ <label name="company_filter"/>
+ <field name="company_filter"/>
+ </group>
<label name="employee"/>
<field name="employee" widget="selection"/>
</xpath>