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>

Reply via email to