+
+
+
+
diff --git a/addons/website_sale/static/src/js/website_sale_tour_shop.js b/addons/website_sale/static/src/js/website_sale_tour_shop.js
index 9b3e5d2eba6..5868ae6cba7 100644
--- a/addons/website_sale/static/src/js/website_sale_tour_shop.js
+++ b/addons/website_sale/static/src/js/website_sale_tour_shop.js
@@ -55,6 +55,7 @@
},
{
waitNot: '.product_price .oe_currency_value:visible:containsExact(1.00)',
+ waitFor: '#snippet_structure',
element: '#wrap img.product_detail_img',
placement: 'top',
title: _t("Update image"),
diff --git a/odoo.py b/odoo.py
index a998c3f8db6..b8f93ad19d5 100755
--- a/odoo.py
+++ b/odoo.py
@@ -68,7 +68,7 @@ def cmd_setup_git():
git_dir = os.getcwd()
if git_dir:
# push sane config for git < 2.0, and hooks
- run('git','config','push.default','simple')
+ #run('git','config','push.default','simple')
# alias
run('git','config','alias.st','status')
# merge bzr style
diff --git a/openerp/addons/base/ir/ir_filters.py b/openerp/addons/base/ir/ir_filters.py
index 6364a2492be..f179a8169f0 100644
--- a/openerp/addons/base/ir/ir_filters.py
+++ b/openerp/addons/base/ir/ir_filters.py
@@ -36,15 +36,30 @@ class ir_filters(osv.osv):
default.update({'name':_('%s (copy)') % name})
return super(ir_filters, self).copy(cr, uid, id, default, context)
- def get_filters(self, cr, uid, model):
+ def _get_action_domain(self, cr, uid, action_id=None):
+ """Return a domain component for matching filters that are visible in the
+ same context (menu/view) as the given action."""
+ if action_id:
+ # filters specific to this menu + global ones
+ return [('action_id', 'in' , [action_id, False])]
+ # only global ones
+ return [('action_id', '=', False)]
+
+ def get_filters(self, cr, uid, model, action_id=None):
"""Obtain the list of filters available for the user on the given model.
+ :param action_id: optional ID of action to restrict filters to this action
+ plus global filters. If missing only global filters are returned.
+ The action does not have to correspond to the model, it may only be
+ a contextual action.
: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``.
+ ``name``, ``is_default``, ``domain``, ``user_id`` (m2o tuple),
+ ``action_id`` (m2o tuple) and ``context`` of the matching ``ir.filters``.
"""
- # available filters: private filters (user_id=uid) and public filters (uid=NULL)
- filter_ids = self.search(cr, uid,
+ # available filters: private filters (user_id=uid) and public filters (uid=NULL),
+ # and filters for the action (action_id=action_id) or global (action_id=NULL)
+ action_domain = self._get_action_domain(cr, uid, action_id)
+ filter_ids = self.search(cr, uid, action_domain +
[('model_id','=',model),('user_id','in',[uid, False])])
my_filters = self.read(cr, uid, filter_ids,
['name', 'is_default', 'domain', 'context', 'user_id'])
@@ -66,7 +81,8 @@ class ir_filters(osv.osv):
:raises openerp.exceptions.Warning: if there is an existing default and
we're not updating it
"""
- existing_default = self.search(cr, uid, [
+ action_domain = self._get_action_domain(cr, uid, vals.get('action_id'))
+ existing_default = self.search(cr, uid, action_domain + [
('model_id', '=', vals['model_id']),
('user_id', '=', False),
('is_default', '=', True)], context=context)
@@ -83,7 +99,9 @@ class ir_filters(osv.osv):
def create_or_replace(self, cr, uid, vals, context=None):
lower_name = vals['name'].lower()
- matching_filters = [f for f in self.get_filters(cr, uid, vals['model_id'])
+ action_id = vals.get('action_id')
+ current_filters = self.get_filters(cr, uid, vals['model_id'], action_id)
+ matching_filters = [f for f in current_filters
if f['name'].lower() == lower_name
# next line looks for matching user_ids (specific or global), i.e.
# f.user_id is False and vals.user_id is False or missing,
@@ -92,18 +110,22 @@ class ir_filters(osv.osv):
if vals.get('is_default'):
if vals.get('user_id'):
- act_ids = self.search(cr, uid, [
+ # Setting new default: any other default that belongs to the user
+ # should be turned off
+ action_domain = self._get_action_domain(cr, uid, action_id)
+ act_ids = self.search(cr, uid, action_domain + [
('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)
+ if act_ids:
+ 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.
+ # replace its definition (considering action_id irrelevant here)
if matching_filters:
self.write(cr, uid, matching_filters[0]['id'], vals, context)
return matching_filters[0]['id']
@@ -114,16 +136,17 @@ class ir_filters(osv.osv):
# Partial constraint, complemented by unique index (see below)
# Still useful to keep because it provides a proper error message when a violation
# occurs, as it shares the same prefix as the unique index.
- ('name_model_uid_unique', 'unique (name, model_id, user_id)', 'Filter names must be unique'),
+ ('name_model_uid_unique', 'unique (name, model_id, user_id, action_id)', 'Filter names must be unique'),
]
def _auto_init(self, cr, context=None):
super(ir_filters, self)._auto_init(cr, context)
# Use unique index to implement unique constraint on the lowercase name (not possible using a constraint)
- cr.execute("SELECT indexname FROM pg_indexes WHERE indexname = 'ir_filters_name_model_uid_unique_index'")
+ cr.execute("DROP INDEX IF EXISTS ir_filters_name_model_uid_unique_index") # drop old index w/o action
+ cr.execute("SELECT indexname FROM pg_indexes WHERE indexname = 'ir_filters_name_model_uid_unique_action_index'")
if not cr.fetchone():
- cr.execute("""CREATE UNIQUE INDEX "ir_filters_name_model_uid_unique_index" ON ir_filters
- (lower(name), model_id, COALESCE(user_id,-1))""")
+ cr.execute("""CREATE UNIQUE INDEX "ir_filters_name_model_uid_unique_action_index" ON ir_filters
+ (lower(name), model_id, COALESCE(user_id,-1), COALESCE(action_id,-1))""")
_columns = {
'name': fields.char('Filter Name', translate=True, required=True),
@@ -133,7 +156,11 @@ 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')
+ 'is_default': fields.boolean('Default filter'),
+ 'action_id': fields.many2one('ir.actions.actions', 'Action', ondelete='cascade',
+ help="The menu action this filter applies to. "
+ "When left empty the filter applies to all menus "
+ "for this model.")
}
_defaults = {
'domain': '[]',
@@ -141,5 +168,6 @@ class ir_filters(osv.osv):
'user_id': lambda self,cr,uid,context=None: uid,
'is_default': False
}
+ _order = 'model_id, name, id desc'
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/addons/base/ir/ir_filters.xml b/openerp/addons/base/ir/ir_filters.xml
index 46242b67ab4..acc16e172b4 100644
--- a/openerp/addons/base/ir/ir_filters.xml
+++ b/openerp/addons/base/ir/ir_filters.xml
@@ -20,6 +20,7 @@
+
@@ -37,6 +38,7 @@
+
diff --git a/openerp/addons/base/ir/ir_ui_menu.py b/openerp/addons/base/ir/ir_ui_menu.py
index 8ace579defb..60014be9e01 100644
--- a/openerp/addons/base/ir/ir_ui_menu.py
+++ b/openerp/addons/base/ir/ir_ui_menu.py
@@ -349,6 +349,18 @@ class ir_ui_menu(osv.osv):
menu_domain = [('parent_id', '=', False)]
return self.search(cr, uid, menu_domain, context=context)
+ def load_menus_root(self, cr, uid, context=None):
+ fields = ['name', 'sequence', 'parent_id', 'action']
+ menu_root_ids = self.get_user_roots(cr, uid, context=context)
+ menu_roots = self.read(cr, uid, menu_root_ids, fields, context=context) if menu_root_ids else []
+ return {
+ 'id': False,
+ 'name': 'root',
+ 'parent_id': [-1, ''],
+ 'children': menu_roots,
+ 'all_menu_ids': menu_root_ids,
+ }
+
def load_menus(self, cr, uid, context=None):
""" Loads all menu items (all applications and their sub-menus).
diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py
index 04b551c1a89..b5231808b5e 100644
--- a/openerp/addons/base/ir/ir_ui_view.py
+++ b/openerp/addons/base/ir/ir_ui_view.py
@@ -986,10 +986,15 @@ class view(osv.osv):
)
qcontext.update(values)
- # TODO: remove this as soon as the following branch is merged
- # lp:~openerp-dev/openerp-web/trunk-module-closure-style-msh
- from openerp.addons.web.controllers.main import module_boot
- qcontext['modules'] = simplejson.dumps(module_boot()) if request else None
+ # TODO: This helper can be used by any template that wants to embedd the backend.
+ # It is currently necessary because the ir.ui.view bundle inheritance does not
+ # match the module dependency graph.
+ def get_modules_order():
+ if request:
+ from openerp.addons.web.controllers.main import module_boot
+ return simplejson.dumps(module_boot())
+ return '[]'
+ qcontext['get_modules_order'] = get_modules_order
def loader(name):
return self.read_template(cr, uid, name, context=context)
diff --git a/openerp/addons/base/res/res_currency_data.xml b/openerp/addons/base/res/res_currency_data.xml
index 77307d056c7..6c0b5179e0d 100644
--- a/openerp/addons/base/res/res_currency_data.xml
+++ b/openerp/addons/base/res/res_currency_data.xml
@@ -1943,18 +1943,6 @@
39.6622695
-
- ROL
- L
- 0.01
- 4
-
-
-
-
- 45638.59
-
-
QARQR
diff --git a/openerp/addons/base/tests/test_ir_filters.py b/openerp/addons/base/tests/test_ir_filters.py
index 04ecca74525..9ca093d77af 100644
--- a/openerp/addons/base/tests/test_ir_filters.py
+++ b/openerp/addons/base/tests/test_ir_filters.py
@@ -5,10 +5,9 @@ from openerp import exceptions
from openerp.tests import common
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']
+ """ Removes values that are not relevant for the test comparisons """
+ d.pop('id', None)
+ d.pop('action_id', None)
return d
class FiltersCase(common.TransactionCase):
diff --git a/openerp/tests/common.py b/openerp/tests/common.py
index 4d4417ee781..50b85555d04 100644
--- a/openerp/tests/common.py
+++ b/openerp/tests/common.py
@@ -5,6 +5,7 @@ helpers and classes to write tests.
"""
import errno
+import glob
import json
import logging
import os
@@ -170,7 +171,6 @@ class HttpCase(TransactionCase):
self.session_id = self.session.sid
self.session.db = DB
openerp.http.root.session_store.save(self.session)
- self.localstorage_path = mkdtemp()
# setup an url opener helper
self.opener = urllib2.OpenerDirector()
self.opener.add_handler(urllib2.UnknownHandler())
@@ -181,7 +181,6 @@ class HttpCase(TransactionCase):
self.opener.addheaders.append(('Cookie', 'session_id=%s' % self.session_id))
def tearDown(self):
- rmtree(self.localstorage_path)
self.registry.leave_test_mode()
super(HttpCase, self).tearDown()
@@ -254,6 +253,11 @@ class HttpCase(TransactionCase):
def phantom_run(self, cmd, timeout):
_logger.info('phantom_run executing %s', ' '.join(cmd))
+
+ ls_glob = os.path.expanduser('~/.qws/share/data/Ofi Labs/PhantomJS/http_localhost_%s.*'%PORT)
+ for i in glob.glob(ls_glob):
+ _logger.info('phantomjs unlink localstorage %s', i)
+ os.unlink(i)
try:
phantom = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError:
@@ -296,7 +300,6 @@ class HttpCase(TransactionCase):
# phantom.args[1] == options
cmd = [
'phantomjs',
- '--local-storage-path', self.localstorage_path,
jsfile, phantomtest, json.dumps(options)
]
self.phantom_run(cmd, timeout)
diff --git a/openerp/tests/phantomtest.js b/openerp/tests/phantomtest.js
index 84f886c5dbb..49da52e07d9 100644
--- a/openerp/tests/phantomtest.js
+++ b/openerp/tests/phantomtest.js
@@ -116,6 +116,8 @@ function PhantomTest() {
phantom.exit(1);
} else {
console.log('loaded', url, status);
+ // clear localstorage leftovers
+ self.page.evaluate(function () { localStorage.clear() });
// process ready
waitFor(function() {
console.log("PhantomTest.run: wait for condition:", ready);