[MERGE] ir.filters now have @is_default and a corresponding API adaptation
Client code usually calls get_filters() to get the list of filters for a particular model, and then create_or_replace() to manage these filters. In both cases a new @is_default attribute is now available - the idea being that the default filter is always applied when a view is newly opened. Global (user_id = False) filters are replaced by user-specific filters when there are any. bzr revid: odo@openerp.com-20121109140828-gpuifdjwrmefg5n2
This commit is contained in:
commit
91e2d25cdd
|
@ -19,6 +19,7 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp import exceptions
|
||||
from osv import osv, fields
|
||||
from tools.translate import _
|
||||
|
||||
|
@ -41,13 +42,47 @@ class ir_filters(osv.osv):
|
|||
def get_filters(self, cr, uid, model):
|
||||
"""Obtain the list of filters available for the user on the given model.
|
||||
|
||||
:return: list of :meth:`~osv.read`-like dicts containing the ``name``,
|
||||
``domain``, ``user_id`` (m2o tuple) and ``context`` of the matching ``ir.filters``.
|
||||
:return: list of :meth:`~osv.read`-like dicts containing the
|
||||
``name``, ``is_default``, ``domain``, ``user_id`` (m2o tuple) and
|
||||
``context`` of the matching ``ir.filters``.
|
||||
"""
|
||||
# available filters: private filters (user_id=uid) and public filters (uid=NULL)
|
||||
act_ids = self.search(cr, uid, [('model_id','=',model),('user_id','in',[uid, False])])
|
||||
my_acts = self.read(cr, uid, act_ids, ['name', 'domain', 'context', 'user_id'])
|
||||
return my_acts
|
||||
filter_ids = self.search(cr, uid,
|
||||
[('model_id','=',model),('user_id','in',[uid, False])])
|
||||
my_filters = self.read(cr, uid, filter_ids,
|
||||
['name', 'is_default', 'domain', 'context', 'user_id'])
|
||||
return my_filters
|
||||
|
||||
def _check_global_default(self, cr, uid, vals, matching_filters, context=None):
|
||||
""" _check_global_default(cursor, UID, dict, list(dict), dict) -> None
|
||||
|
||||
Checks if there is a global default for the model_id requested.
|
||||
|
||||
If there is, and the default is different than the record being written
|
||||
(-> we're not updating the current global default), raise an error
|
||||
to avoid users unknowingly overwriting existing global defaults (they
|
||||
have to explicitly remove the current default before setting a new one)
|
||||
|
||||
This method should only be called if ``vals`` is trying to set
|
||||
``is_default``
|
||||
|
||||
:raises openerp.exceptions.Warning: if there is an existing default and
|
||||
we're not updating it
|
||||
"""
|
||||
existing_default = self.search(cr, uid, [
|
||||
('model_id', '=', vals['model_id']),
|
||||
('user_id', '=', False),
|
||||
('is_default', '=', True)], context=context)
|
||||
|
||||
if not existing_default: return
|
||||
if matching_filters and \
|
||||
(matching_filters[0]['id'] == existing_default[0]):
|
||||
return
|
||||
|
||||
raise exceptions.Warning(
|
||||
_("There is already a shared filter set as default for %(model)s, delete or change it before setting a new default") % {
|
||||
'model': vals['model_id']
|
||||
})
|
||||
|
||||
def create_or_replace(self, cr, uid, vals, context=None):
|
||||
lower_name = vals['name'].lower()
|
||||
|
@ -57,11 +92,25 @@ class ir_filters(osv.osv):
|
|||
# f.user_id is False and vals.user_id is False or missing,
|
||||
# or f.user_id.id == vals.user_id
|
||||
if (f['user_id'] and f['user_id'][0]) == vals.get('user_id', False)]
|
||||
|
||||
if vals.get('is_default'):
|
||||
if vals.get('user_id'):
|
||||
act_ids = self.search(cr, uid, [
|
||||
('model_id', '=', vals['model_id']),
|
||||
('user_id', '=', vals['user_id']),
|
||||
('is_default', '=', True),
|
||||
], context=context)
|
||||
self.write(cr, uid, act_ids, {'is_default': False}, context=context)
|
||||
else:
|
||||
self._check_global_default(
|
||||
cr, uid, vals, matching_filters, context=None)
|
||||
|
||||
# When a filter exists for the same (name, model, user) triple, we simply
|
||||
# replace its definition.
|
||||
if matching_filters:
|
||||
self.write(cr, uid, matching_filters[0]['id'], vals, context)
|
||||
return matching_filters[0]['id']
|
||||
|
||||
return self.create(cr, uid, vals, context)
|
||||
|
||||
_sql_constraints = [
|
||||
|
@ -87,11 +136,13 @@ class ir_filters(osv.osv):
|
|||
'domain': fields.text('Domain', required=True),
|
||||
'context': fields.text('Context', required=True),
|
||||
'model_id': fields.selection(_list_all_models, 'Model', required=True),
|
||||
'is_default': fields.boolean('Default filter')
|
||||
}
|
||||
_defaults = {
|
||||
'domain': '[]',
|
||||
'context':'{}',
|
||||
'user_id': lambda self,cr,uid,context=None: uid,
|
||||
'is_default': False
|
||||
}
|
||||
|
||||
ir_filters()
|
||||
|
|
|
@ -11,9 +11,11 @@ See the :ref:`test-framework` section in the :ref:`features` list.
|
|||
from . import test_expression, test_html_sanitize, test_ir_sequence, test_orm,\
|
||||
test_fields, test_basecase, \
|
||||
test_view_validation, test_uninstall, test_misc, test_db_cursor
|
||||
from . import test_ir_filters
|
||||
|
||||
fast_suite = [
|
||||
test_ir_sequence,
|
||||
test_ir_filters
|
||||
]
|
||||
|
||||
checks = [
|
||||
|
|
|
@ -25,7 +25,7 @@ if not DB and hasattr(threading.current_thread(), 'dbname'):
|
|||
HOST = '127.0.0.1'
|
||||
|
||||
ADMIN_USER = 'admin'
|
||||
ADMIN_USER_ID = 1
|
||||
ADMIN_USER_ID = openerp.SUPERUSER_ID
|
||||
ADMIN_PASSWORD = 'admin'
|
||||
|
||||
def start_openerp():
|
||||
|
|
|
@ -0,0 +1,264 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import functools
|
||||
|
||||
import openerp
|
||||
from openerp import exceptions
|
||||
from . import common
|
||||
|
||||
class Fixtures(object):
|
||||
def __init__(self, *args):
|
||||
self.fixtures = args
|
||||
|
||||
def __call__(self, fn):
|
||||
@functools.wraps(fn)
|
||||
def wrapper(case):
|
||||
for model, vars in self.fixtures:
|
||||
case.registry(model).create(
|
||||
case.cr, common.ADMIN_USER_ID, vars, {})
|
||||
|
||||
fn(case)
|
||||
return wrapper
|
||||
def fixtures(*args):
|
||||
return Fixtures(*args)
|
||||
|
||||
def noid(d):
|
||||
""" Removes `id` key from a dict so we don't have to keep these things
|
||||
around when trying to match
|
||||
"""
|
||||
if 'id' in d: del d['id']
|
||||
return d
|
||||
|
||||
class TestGetFilters(common.TransactionCase):
|
||||
USER_ID = 3
|
||||
USER = (3, u'Demo User')
|
||||
|
||||
@fixtures(
|
||||
('ir.filters', dict(name='a', user_id=USER_ID, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='b', user_id=USER_ID, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='c', user_id=USER_ID, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='d', user_id=USER_ID, model_id='ir.filters')),
|
||||
)
|
||||
def test_own_filters(self):
|
||||
filters = self.registry('ir.filters').get_filters(
|
||||
self.cr, self.USER_ID, 'ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', is_default=False, user_id=self.USER, domain='[]', context='{}'),
|
||||
dict(name='b', is_default=False, user_id=self.USER, domain='[]', context='{}'),
|
||||
dict(name='c', is_default=False, user_id=self.USER, domain='[]', context='{}'),
|
||||
dict(name='d', is_default=False, user_id=self.USER, domain='[]', context='{}'),
|
||||
])
|
||||
|
||||
@fixtures(
|
||||
('ir.filters', dict(name='a', user_id=False, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='b', user_id=False, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='c', user_id=False, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='d', user_id=False, model_id='ir.filters')),
|
||||
)
|
||||
def test_global_filters(self):
|
||||
filters = self.registry('ir.filters').get_filters(
|
||||
self.cr, self.USER_ID, 'ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', is_default=False, user_id=False, domain='[]', context='{}'),
|
||||
dict(name='b', is_default=False, user_id=False, domain='[]', context='{}'),
|
||||
dict(name='c', is_default=False, user_id=False, domain='[]', context='{}'),
|
||||
dict(name='d', is_default=False, user_id=False, domain='[]', context='{}'),
|
||||
])
|
||||
|
||||
@fixtures(
|
||||
('ir.filters', dict(name='a', user_id=False, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='b', user_id=common.ADMIN_USER_ID, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='c', user_id=USER_ID, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='d', user_id=common.ADMIN_USER_ID, model_id='ir.filters')),
|
||||
)
|
||||
def test_no_third_party_filters(self):
|
||||
filters = self.registry('ir.filters').get_filters(
|
||||
self.cr, self.USER_ID, 'ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', is_default=False, user_id=False, domain='[]', context='{}'),
|
||||
dict(name='c', is_default=False, user_id=self.USER, domain='[]', context='{}'),
|
||||
])
|
||||
|
||||
class TestOwnDefaults(common.TransactionCase):
|
||||
USER_ID = 3
|
||||
USER = (3, u'Demo User')
|
||||
|
||||
def test_new_no_filter(self):
|
||||
"""
|
||||
When creating a @is_default filter with no existing filter, that new
|
||||
filter gets the default flag
|
||||
"""
|
||||
Filters = self.registry('ir.filters')
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
'name': 'a',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': self.USER_ID,
|
||||
'is_default': True,
|
||||
})
|
||||
filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', user_id=self.USER, is_default=True,
|
||||
domain='[]', context='{}')
|
||||
])
|
||||
|
||||
@fixtures(
|
||||
('ir.filters', dict(name='a', user_id=USER_ID, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='b', user_id=USER_ID, model_id='ir.filters')),
|
||||
)
|
||||
def test_new_filter_not_default(self):
|
||||
"""
|
||||
When creating a @is_default filter with existing non-default filters,
|
||||
the new filter gets the flag
|
||||
"""
|
||||
Filters = self.registry('ir.filters')
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
'name': 'c',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': self.USER_ID,
|
||||
'is_default': True,
|
||||
})
|
||||
filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', user_id=self.USER, is_default=False, domain='[]', context='{}'),
|
||||
dict(name='b', user_id=self.USER, is_default=False, domain='[]', context='{}'),
|
||||
dict(name='c', user_id=self.USER, is_default=True, domain='[]', context='{}'),
|
||||
])
|
||||
|
||||
@fixtures(
|
||||
('ir.filters', dict(name='a', user_id=USER_ID, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='b', is_default=True, user_id=USER_ID, model_id='ir.filters')),
|
||||
)
|
||||
def test_new_filter_existing_default(self):
|
||||
"""
|
||||
When creating a @is_default filter where an existing filter is already
|
||||
@is_default, the flag should be *moved* from the old to the new filter
|
||||
"""
|
||||
Filters = self.registry('ir.filters')
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
'name': 'c',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': self.USER_ID,
|
||||
'is_default': True,
|
||||
})
|
||||
filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', user_id=self.USER, is_default=False, domain='[]', context='{}'),
|
||||
dict(name='b', user_id=self.USER, is_default=False, domain='[]', context='{}'),
|
||||
dict(name='c', user_id=self.USER, is_default=True, domain='[]', context='{}'),
|
||||
])
|
||||
|
||||
@fixtures(
|
||||
('ir.filters', dict(name='a', user_id=USER_ID, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='b', is_default=True, user_id=USER_ID, model_id='ir.filters')),
|
||||
)
|
||||
def test_update_filter_set_default(self):
|
||||
"""
|
||||
When updating an existing filter to @is_default, if an other filter
|
||||
already has the flag the flag should be moved
|
||||
"""
|
||||
Filters = self.registry('ir.filters')
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
'name': 'a',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': self.USER_ID,
|
||||
'is_default': True,
|
||||
})
|
||||
filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', user_id=self.USER, is_default=True, domain='[]', context='{}'),
|
||||
dict(name='b', user_id=self.USER, is_default=False, domain='[]', context='{}'),
|
||||
])
|
||||
|
||||
class TestGlobalDefaults(common.TransactionCase):
|
||||
USER_ID = 3
|
||||
|
||||
@fixtures(
|
||||
('ir.filters', dict(name='a', user_id=False, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='b', user_id=False, model_id='ir.filters')),
|
||||
)
|
||||
def test_new_filter_not_default(self):
|
||||
"""
|
||||
When creating a @is_default filter with existing non-default filters,
|
||||
the new filter gets the flag
|
||||
"""
|
||||
Filters = self.registry('ir.filters')
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
'name': 'c',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': False,
|
||||
'is_default': True,
|
||||
})
|
||||
filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', user_id=False, is_default=False, domain='[]', context='{}'),
|
||||
dict(name='b', user_id=False, is_default=False, domain='[]', context='{}'),
|
||||
dict(name='c', user_id=False, is_default=True, domain='[]', context='{}'),
|
||||
])
|
||||
|
||||
@fixtures(
|
||||
('ir.filters', dict(name='a', user_id=False, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='b', is_default=True, user_id=False, model_id='ir.filters')),
|
||||
)
|
||||
def test_new_filter_existing_default(self):
|
||||
"""
|
||||
When creating a @is_default filter where an existing filter is already
|
||||
@is_default, an error should be generated
|
||||
"""
|
||||
Filters = self.registry('ir.filters')
|
||||
with self.assertRaises(exceptions.Warning):
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
'name': 'c',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': False,
|
||||
'is_default': True,
|
||||
})
|
||||
|
||||
@fixtures(
|
||||
('ir.filters', dict(name='a', user_id=False, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='b', is_default=True, user_id=False, model_id='ir.filters')),
|
||||
)
|
||||
def test_update_filter_set_default(self):
|
||||
"""
|
||||
When updating an existing filter to @is_default, if an other filter
|
||||
already has the flag an error should be generated
|
||||
"""
|
||||
Filters = self.registry('ir.filters')
|
||||
|
||||
with self.assertRaises(exceptions.Warning):
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
'name': 'a',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': False,
|
||||
'is_default': True,
|
||||
})
|
||||
|
||||
@fixtures(
|
||||
('ir.filters', dict(name='a', user_id=False, model_id='ir.filters')),
|
||||
('ir.filters', dict(name='b', is_default=True, user_id=False, model_id='ir.filters')),
|
||||
)
|
||||
def test_update_default_filter(self):
|
||||
"""
|
||||
Replacing the current default global filter should not generate any error
|
||||
"""
|
||||
Filters = self.registry('ir.filters')
|
||||
context_value = "{'some_key': True}"
|
||||
Filters.create_or_replace(self.cr, self.USER_ID, {
|
||||
'name': 'b',
|
||||
'model_id': 'ir.filters',
|
||||
'user_id': False,
|
||||
'context': context_value,
|
||||
'is_default': True,
|
||||
})
|
||||
filters = Filters.get_filters(self.cr, self.USER_ID, 'ir.filters')
|
||||
|
||||
self.assertItemsEqual(map(noid, filters), [
|
||||
dict(name='a', user_id=False, is_default=False, domain='[]', context='{}'),
|
||||
dict(name='b', user_id=False, is_default=True, domain='[]', context=context_value),
|
||||
])
|
Loading…
Reference in New Issue