diff --git a/modules/attendance/__init__.py b/modules/attendance/__init__.py index c5317703f0..2e9178683c 100644 --- a/modules/attendance/__init__.py +++ b/modules/attendance/__init__.py @@ -3,13 +3,14 @@ from trytond.pool import Pool -from . import attendance +from . import attendance, ir __all__ = ['register'] def register(): Pool.register( + ir.Rule, attendance.Line, attendance.Period, attendance.SheetLine, diff --git a/modules/attendance/ir.py b/modules/attendance/ir.py new file mode 100644 index 0000000000..5b1f46fb99 --- /dev/null +++ b/modules/attendance/ir.py @@ -0,0 +1,26 @@ +# 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.pool import Pool, PoolMeta + + +class Rule(metaclass=PoolMeta): + __name__ = 'ir.rule' + + @classmethod + def _get_context(cls, model_name): + pool = Pool() + User = pool.get('res.user') + context = super()._get_context(model_name) + if model_name == 'attendance.line': + context['employees'] = User.get_employees() + return context + + @classmethod + def _get_cache_key(cls, model_name): + pool = Pool() + User = pool.get('res.user') + key = super()._get_cache_key(model_name) + if model_name == 'attendance.line': + key = (*key, User.get_employees()) + return key diff --git a/modules/company/CHANGELOG b/modules/company/CHANGELOG index 93add91fec..5277806e68 100644 --- a/modules/company/CHANGELOG +++ b/modules/company/CHANGELOG @@ -1,3 +1,4 @@ +* Remove employee and employees from evaluation context of rule domain * Define when set or reset employee field Version 6.8.0 - 2023-05-01 diff --git a/modules/company/ir.py b/modules/company/ir.py index 921ec906f9..f8199c8ec4 100644 --- a/modules/company/ir.py +++ b/modules/company/ir.py @@ -1,10 +1,9 @@ # 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 ( - EvalEnvironment, ModelSQL, ModelView, dualmethod, fields) +from trytond.model import ModelSQL, ModelView, dualmethod, fields from trytond.pool import Pool, PoolMeta from trytond.tools import timezone as tz -from trytond.transaction import Transaction, without_check_access +from trytond.transaction import Transaction class Sequence(metaclass=PoolMeta): @@ -49,46 +48,21 @@ class Rule(metaclass=PoolMeta): def __setup__(cls): super().__setup__() cls.domain.help += ( - '\n- "employee" from the current user' - '\n- "employees" as list of ids from the current user' '\n- "companies" as list of ids from the current user') @classmethod def _get_cache_key(cls, model_name): + pool = Pool() + User = pool.get('res.user') key = super()._get_cache_key(model_name) - # XXX Use company from context instead of browse to prevent infinite - # loop, but the cache is cleared when User is written. - context = Transaction().context - return key + ( - context.get('company'), - context.get('employee'), - context.get('company_filter'), - ) + return (*key, User.get_companies()) @classmethod def _get_context(cls, model_name): pool = Pool() User = pool.get('res.user') - Employee = pool.get('company.employee') context = super()._get_context(model_name) - # Use root to avoid infinite loop when accessing user attributes - user_id = Transaction().user - with Transaction().set_user(0): - user = User(user_id) - if user.employee: - with without_check_access(), \ - Transaction().set_context(_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'] = [] + context['companies'] = User.get_companies() return context diff --git a/modules/company/res.py b/modules/company/res.py index a9996693f9..91361951d3 100644 --- a/modules/company/res.py +++ b/modules/company/res.py @@ -2,6 +2,7 @@ # this repository contains the full copyright notices and license terms. from sql import Null +from trytond.cache import Cache from trytond.model import ModelSQL, fields from trytond.pool import Pool, PoolMeta from trytond.pyson import Eval @@ -18,6 +19,28 @@ class UserCompany(ModelSQL): 'company.company', "Company", ondelete='CASCADE', required=True) + @classmethod + def create(cls, vlist): + pool = Pool() + User = pool.get('res.user') + records = super().create(vlist) + User._get_companies_cache.clear() + return records + + @classmethod + def write(cls, *args): + pool = Pool() + User = pool.get('res.user') + super().write(*args) + User._get_companies_cache.clear() + + @classmethod + def delete(cls, records): + pool = Pool() + User = pool.get('res.user') + super().delete(records) + User._get_companies_cache.clear() + class UserEmployee(ModelSQL): 'User - Employee' @@ -27,6 +50,28 @@ class UserEmployee(ModelSQL): employee = fields.Many2One( 'company.employee', "Employee", ondelete='CASCADE', required=True) + @classmethod + def create(cls, vlist): + pool = Pool() + User = pool.get('res.user') + records = super().create(vlist) + User._get_employees_cache.clear() + return records + + @classmethod + def write(cls, *args): + pool = Pool() + User = pool.get('res.user') + super().write(*args) + User._get_employees_cache.clear() + + @classmethod + def delete(cls, records): + pool = Pool() + User = pool.get('res.user') + super().delete(records) + User._get_employees_cache.clear() + class User(metaclass=PoolMeta): __name__ = 'res.user' @@ -57,6 +102,8 @@ class User(metaclass=PoolMeta): ('all', "All"), ], "Company Filter", help="Define records of which companies are shown.") + _get_companies_cache = Cache(__name__ + '.get_companies', context=False) + _get_employees_cache = Cache(__name__ + '.get_employees', context=False) @classmethod def __setup__(cls): @@ -140,6 +187,50 @@ class User(metaclass=PoolMeta): res['employees'] = [e.id for e in user.employees] return res + @classmethod + def get_companies(cls): + ''' + Return an ordered tuple of company ids for the user + ''' + transaction = Transaction() + user_id = transaction.user + companies = cls._get_companies_cache.get(user_id) + if companies is not None: + return companies + with transaction.set_user(0): + user = cls(user_id) + if user.company_filter == 'one': + companies = [user.company.id] if user.company else [] + elif user.company_filter == 'all': + companies = [c.id for c in user.companies] + else: + companies = [] + companies = tuple(companies) + cls._get_companies_cache.set(user_id, companies) + return companies + + @classmethod + def get_employees(cls): + ''' + Return an ordered tuple of employee ids for the user + ''' + transaction = Transaction() + user_id = transaction.user + employees = cls._get_employees_cache.get(user_id) + if employees is not None: + return employees + with transaction.set_user(0): + user = cls(user_id) + if user.company_filter == 'one': + employees = [user.employee.id] if user.employee else [] + elif user.company_filter == 'all': + employees = [e.id for e in user.employees] + else: + employees = [] + employees = tuple(employees) + cls._get_employees_cache.set(user_id, employees) + return employees + @classmethod def read(cls, ids, fields_names): user_id = Transaction().user @@ -189,8 +280,6 @@ class User(metaclass=PoolMeta): @classmethod def write(cls, *args): - pool = Pool() - Rule = pool.get('ir.rule') - super(User, cls).write(*args) - # Restart the cache on the domain_get method - Rule._domain_get_cache.clear() + super().write(*args) + cls._get_companies_cache.clear() + cls._get_employees_cache.clear() diff --git a/modules/purchase_requisition/__init__.py b/modules/purchase_requisition/__init__.py index ddfac525a9..06abaa2fa7 100644 --- a/modules/purchase_requisition/__init__.py +++ b/modules/purchase_requisition/__init__.py @@ -3,11 +3,12 @@ from trytond.pool import Pool -from . import purchase +from . import ir, purchase def register(): Pool.register( + ir.Rule, purchase.PurchaseRequest, purchase.PurchaseRequisition, purchase.PurchaseRequisitionLine, diff --git a/modules/purchase_requisition/ir.py b/modules/purchase_requisition/ir.py new file mode 100644 index 0000000000..baad2791c2 --- /dev/null +++ b/modules/purchase_requisition/ir.py @@ -0,0 +1,26 @@ +# 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.pool import Pool, PoolMeta + + +class Rule(metaclass=PoolMeta): + __name__ = 'ir.rule' + + @classmethod + def _get_context(cls, model_name): + pool = Pool() + User = pool.get('res.user') + context = super()._get_context(model_name) + if model_name == 'purchase.requisition': + context['employees'] = User.get_employees() + return context + + @classmethod + def _get_cache_key(cls, model_name): + pool = Pool() + User = pool.get('res.user') + key = super()._get_cache_key(model_name) + if model_name == 'purchase.requisition': + key = (*key, User.get_employees()) + return key diff --git a/modules/timesheet/__init__.py b/modules/timesheet/__init__.py index b763272487..5e4392ef75 100644 --- a/modules/timesheet/__init__.py +++ b/modules/timesheet/__init__.py @@ -2,13 +2,14 @@ # this repository contains the full copyright notices and license terms. from trytond.pool import Pool -from . import line, routes, user, work +from . import ir, line, routes, user, work __all__ = ['register', 'routes'] def register(): Pool.register( + ir.Rule, work.Work, work.WorkContext, line.Line, diff --git a/modules/timesheet/ir.py b/modules/timesheet/ir.py new file mode 100644 index 0000000000..465430b4e8 --- /dev/null +++ b/modules/timesheet/ir.py @@ -0,0 +1,26 @@ +# 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.pool import Pool, PoolMeta + + +class Rule(metaclass=PoolMeta): + __name__ = 'ir.rule' + + @classmethod + def _get_context(cls, model_name): + pool = Pool() + User = pool.get('res.user') + context = super()._get_context(model_name) + if model_name == 'timesheet.line': + context['employees'] = User.get_employees() + return context + + @classmethod + def _get_cache_key(cls, model_name): + pool = Pool() + User = pool.get('res.user') + key = super()._get_cache_key(model_name) + if model_name == 'timesheet.line': + key = (*key, User.get_employees()) + return key