diff --git a/addons/web/__openerp__.py b/addons/web/__openerp__.py
index 269aa13d58e..48903312b44 100644
--- a/addons/web/__openerp__.py
+++ b/addons/web/__openerp__.py
@@ -1,7 +1,7 @@
{
'name': 'Web',
'category': 'Hidden',
- 'version': '7.0.1.0',
+ 'version': '1.0',
'description':
"""
OpenERP Web core module.
@@ -13,6 +13,7 @@ This module provides the core of the OpenERP Web Client.
'auto_install': True,
'post_load': 'wsgi_postload',
'js' : [
+ "static/src/fixbind.js",
"static/lib/datejs/globalization/en-US.js",
"static/lib/datejs/core.js",
"static/lib/datejs/parser.js",
@@ -76,6 +77,7 @@ This module provides the core of the OpenERP Web Client.
"static/test/class.js",
"static/test/registry.js",
"static/test/form.js",
+ "static/test/data.js",
"static/test/list-utils.js",
"static/test/formats.js",
"static/test/rpc.js",
diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py
index b7071eff9e2..8683ef177bc 100644
--- a/addons/web/controllers/main.py
+++ b/addons/web/controllers/main.py
@@ -310,7 +310,7 @@ def fs2web(path):
"""convert FS path into web path"""
return '/'.join(path.split(os.path.sep))
-def manifest_glob(extension, addons=None, db=None):
+def manifest_glob(extension, addons=None, db=None, include_remotes=False):
if addons is None:
addons = module_boot(db=db)
else:
@@ -324,8 +324,12 @@ def manifest_glob(extension, addons=None, db=None):
addons_path = os.path.join(manifest['addons_path'], '')[:-1]
globlist = manifest.get(extension, [])
for pattern in globlist:
- for path in glob.glob(os.path.normpath(os.path.join(addons_path, addon, pattern))):
- r.append((path, fs2web(path[len(addons_path):])))
+ if pattern.startswith(('http://', 'https://', '//')):
+ if include_remotes:
+ r.append((None, pattern))
+ else:
+ for path in glob.glob(os.path.normpath(os.path.join(addons_path, addon, pattern))):
+ r.append((path, fs2web(path[len(addons_path):])))
return r
def manifest_list(extension, mods=None, db=None):
@@ -333,14 +337,16 @@ def manifest_list(extension, mods=None, db=None):
mods: a comma separated string listing modules
db: a database name (return all installed modules in that database)
"""
+ files = manifest_glob(extension, addons=mods, db=db, include_remotes=True)
if not req.debug:
path = '/web/webclient/' + extension
if mods is not None:
path += '?' + urllib.urlencode({'mods': mods})
elif db:
path += '?' + urllib.urlencode({'db': db})
- return [path]
- files = manifest_glob(extension, addons=mods, db=db)
+
+ remotes = [wp for fp, wp in files if fp is None]
+ return [path] + remotes
return [wp for _fp, wp in files]
def get_last_modified(files):
@@ -1204,19 +1210,19 @@ class Binary(openerpweb.Controller):
headers = [('Content-Type', 'image/png')]
etag = req.httprequest.headers.get('If-None-Match')
hashed_session = hashlib.md5(req.session_id).hexdigest()
+ retag = hashed_session
id = None if not id else simplejson.loads(id)
if type(id) is list:
id = id[0] # m2o
- if etag:
- if not id and hashed_session == etag:
- return werkzeug.wrappers.Response(status=304)
- else:
- date = Model.read([id], [last_update], req.context)[0].get(last_update)
- if hashlib.md5(date).hexdigest() == etag:
- return werkzeug.wrappers.Response(status=304)
-
- retag = hashed_session
try:
+ if etag:
+ if not id and hashed_session == etag:
+ return werkzeug.wrappers.Response(status=304)
+ else:
+ date = Model.read([id], [last_update], req.context)[0].get(last_update)
+ if hashlib.md5(date).hexdigest() == etag:
+ return werkzeug.wrappers.Response(status=304)
+
if not id:
res = Model.default_get([field], req.context).get(field)
image_base64 = res
diff --git a/addons/web/http.py b/addons/web/http.py
index 67d71ac7d37..2dc41c8cad9 100644
--- a/addons/web/http.py
+++ b/addons/web/http.py
@@ -121,6 +121,13 @@ class WebRequest(object):
# we use _ as seprator where RFC2616 uses '-'
self.lang = lang.replace('-', '_')
+ @contextlib.contextmanager
+ def registry_cr(self):
+ dbname = self.session._db or openerp.addons.web.controllers.main.db_monodb(self)
+ registry = openerp.modules.registry.RegistryManager.get(dbname.lower())
+ with registry.cursor() as cr:
+ yield (registry, cr)
+
def reject_nonliteral(dct):
if '__ref' in dct:
raise ValueError(
@@ -298,6 +305,8 @@ class HttpRequest(WebRequest):
#_logger.debug("%s --> %s.%s %r", self.httprequest.method, method.im_class.__name__, method.__name__, akw)
try:
r = method(**self.params)
+ except werkzeug.exceptions.HTTPException, e:
+ r = e
except Exception, e:
_logger.exception("An exception occured during an http request")
se = serialize_exception(e)
@@ -307,11 +316,13 @@ class HttpRequest(WebRequest):
'data': se
}
r = werkzeug.exceptions.InternalServerError(cgi.escape(simplejson.dumps(error)))
- if self.debug or 1:
- if isinstance(r, (werkzeug.wrappers.BaseResponse, werkzeug.exceptions.HTTPException)):
- _logger.debug('<-- %s', r)
- else:
- _logger.debug("<-- size: %s", len(r))
+ else:
+ if not r:
+ r = werkzeug.wrappers.Response(status=204) # no content
+ if isinstance(r, (werkzeug.wrappers.BaseResponse, werkzeug.exceptions.HTTPException)):
+ _logger.debug('<-- %s', r)
+ else:
+ _logger.debug("<-- size: %s", len(r))
return r
def make_response(self, data, headers=None, cookies=None):
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index f357f6ac2e6..884dc41a9f9 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -913,9 +913,7 @@ instance.web.Menu = instance.web.Widget.extend({
self.reflow();
// launch the fetch of needaction counters, asynchronous
if (!_.isEmpty(menu_data.all_menu_ids)) {
- this.rpc("/web/menu/load_needaction", {menu_ids: menu_data.all_menu_ids}).done(function(r) {
- self.on_needaction_loaded(r);
- });
+ this.do_load_needaction(menu_data.all_menu_ids);
}
});
var lazyreflow = _.debounce(this.reflow.bind(this), 200);
@@ -941,7 +939,7 @@ instance.web.Menu = instance.web.Widget.extend({
this.data = {data: data};
this.renderElement();
this.$secondary_menus.html(QWeb.render("Menu.secondary", { widget : this }));
- this.$el.on('click', 'a[data-menu]', this.on_menu_click);
+ this.$el.on('click', 'a[data-menu]', this.on_top_menu_click);
// Hide second level submenus
this.$secondary_menus.find('.oe_menu_toggler').siblings('.oe_secondary_submenu').hide();
if (self.current_menu) {
@@ -950,6 +948,16 @@ instance.web.Menu = instance.web.Widget.extend({
this.trigger('menu_loaded', data);
this.has_been_loaded.resolve();
},
+ do_load_needaction: function (menu_ids) {
+ var self = this;
+ menu_ids = _.reject(menu_ids, _.isEmpty);
+ if (_.isEmpty(menu_ids)) {
+ return $.when();
+ }
+ return this.rpc("/web/menu/load_needaction", {'menu_ids': menu_ids}).done(function(r) {
+ self.on_needaction_loaded(r);
+ });
+ },
on_needaction_loaded: function(data) {
var self = this;
this.needaction_data = data;
@@ -1081,11 +1089,38 @@ instance.web.Menu = instance.web.Widget.extend({
}
this.open_menu(id);
},
+ do_reload_needaction: function () {
+ var self = this;
+ if (self.current_menu) {
+ self.do_load_needaction([self.current_menu]).then(function () {
+ self.trigger("need_action_reloaded");
+ });
+ }
+ },
/**
* Jquery event handler for menu click
*
* @param {Event} ev the jquery event
*/
+ on_top_menu_click: function(ev) {
+ var self = this;
+ var id = $(ev.currentTarget).data('menu');
+ var menu_ids = [id];
+ var menu = _.filter(this.data.data.children, function (menu) {return menu.id == id;})[0];
+ function add_menu_ids (menu) {
+ if (menu.children) {
+ _.each(menu.children, function (menu) {
+ menu_ids.push(menu.id);
+ add_menu_ids(menu);
+ });
+ }
+ };
+ add_menu_ids(menu);
+ self.do_load_needaction(menu_ids).then(function () {
+ self.trigger("need_action_reloaded");
+ });
+ this.on_menu_click(ev);
+ },
on_menu_click: function(ev) {
ev.preventDefault();
var needaction = $(ev.target).is('div.oe_menu_counter');
diff --git a/addons/web/static/src/js/corelib.js b/addons/web/static/src/js/corelib.js
index c4bb81117f8..116ddf2e8c2 100644
--- a/addons/web/static/src/js/corelib.js
+++ b/addons/web/static/src/js/corelib.js
@@ -1144,7 +1144,8 @@ instance.web.JsonRPC = instance.web.Class.extend(instance.web.PropertiesMixin, {
}
qs = '?' + $.param(params);
}
- return this.prefix + path + qs;
+ var prefix = _.any(['http://', 'https://', '//'], _.bind(_.str.startsWith, null, path)) ? '' : this.prefix;
+ return prefix + path + qs;
},
});
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 6a1dc019f95..32e86d69bed 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -91,6 +91,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
init: function(parent, dataset, view_id, options) {
var self = this;
this._super(parent);
+ this.ViewManager = parent;
this.set_default_options(options);
this.dataset = dataset;
this.model = dataset.model;
@@ -720,6 +721,8 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
return this.save().done(function(result) {
self.trigger("save", result);
self.to_view_mode();
+ }).then(function(result) {
+ self.ViewManager.ActionManager.__parentedParent.menu.do_reload_needaction();
});
},
on_button_cancel: function(event) {
@@ -2901,7 +2904,7 @@ instance.web.form.FieldRadio = instance.web.form.AbstractField.extend(instance.w
var domain = instance.web.pyeval.eval('domain', this.build_domain()) || [];
if (! _.isEqual(self.domain, domain)) {
self.domain = domain;
- var ds = new instance.web.DataSet(self, self.field.relation);
+ var ds = new instance.web.DataSetStatic(self, self.field.relation, self.build_context());
ds.call('search', [self.domain])
.then(function (records) {
ds.name_get(records).then(function (records) {
@@ -3151,6 +3154,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
instance.web.form.CompletionFieldMixin.init.call(this);
this.set({'value': false});
this.display_value = {};
+ this.display_value_backup = {};
this.last_search = [];
this.floating = false;
this.current_display = null;
@@ -3234,6 +3238,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
);
pop.on('write_completed', self, function(){
self.display_value = {};
+ self.display_value_backup = {};
self.render_value();
self.focus();
});
@@ -3284,6 +3289,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
if (self.last_search.length > 0) {
if (self.last_search[0][0] != self.get("value")) {
self.display_value = {};
+ self.display_value_backup = {};
self.display_value["" + self.last_search[0][0]] = self.last_search[0][1];
self.reinit_value(self.last_search[0][0]);
} else {
@@ -3349,6 +3355,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
var item = ui.item;
if (item.id) {
self.display_value = {};
+ self.display_value_backup = {};
self.display_value["" + item.id] = item.name;
self.reinit_value(item.id);
} else if (item.action) {
@@ -3394,6 +3401,11 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
this.alive(dataset.name_get([self.get("value")])).done(function(data) {
self.display_value["" + self.get("value")] = data[0][1];
self.render_value(true);
+ }).fail( function (data, event) {
+ // avoid displaying crash errors as many2One should be name_get compliant
+ event.preventDefault();
+ self.display_value["" + self.get("value")] = self.display_value_backup["" + self.get("value")];
+ self.render_value(true);
});
}
},
@@ -3437,9 +3449,13 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
var self = this;
if (value_ instanceof Array) {
this.display_value = {};
+ this.display_value_backup = {}
if (! this.options.always_reload) {
this.display_value["" + value_[0]] = value_[1];
}
+ else {
+ this.display_value_backup["" + value_[0]] = value_[1];
+ }
value_ = value_[0];
}
value_ = value_ || false;
@@ -3450,6 +3466,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
},
add_id: function(id) {
this.display_value = {};
+ this.display_value_backup = {};
this.reinit_value(id);
},
is_false: function() {
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index 0737281e199..fdb2eeee329 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -522,6 +522,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
return x;
}
});
+ this.ActionManager = parent;
this.views = {};
this.flags = flags || {};
this.registry = instance.web.views;
@@ -1253,6 +1254,7 @@ instance.web.View = instance.web.Widget.extend({
view_type: undefined,
init: function(parent, dataset, view_id, options) {
this._super(parent);
+ this.ViewManager = parent;
this.dataset = dataset;
this.view_id = view_id;
this.set_default_options(options);
@@ -1324,7 +1326,6 @@ instance.web.View = instance.web.Widget.extend({
}
};
var context = new instance.web.CompoundContext(dataset.get_context(), action_data.context || {});
-
var handler = function (action) {
if (action && action.constructor == Object) {
var ncontext = new instance.web.CompoundContext(context);
@@ -1361,7 +1362,11 @@ instance.web.View = instance.web.Widget.extend({
}
}
args.push(context);
- return dataset.call_button(action_data.name, args).then(handler);
+ return dataset.call_button(action_data.name, args).then(handler).then(function () {
+ if (self.ViewManager.ActionManager) {
+ self.ViewManager.ActionManager.__parentedParent.menu.do_reload_needaction();
+ }
+ });
} else if (action_data.type=="action") {
return this.rpc('/web/action/load', {
action_id: action_data.name,
diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js
index d89700e9730..0600f68b94b 100644
--- a/addons/web_kanban/static/src/js/kanban.js
+++ b/addons/web_kanban/static/src/js/kanban.js
@@ -265,10 +265,13 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
var remaining = groups.length - 1,
groups_array = [];
return $.when.apply(null, _.map(groups, function (group, index) {
+ var def = $.when([]);
var dataset = new instance.web.DataSetSearch(self, self.dataset.model,
new instance.web.CompoundContext(self.dataset.get_context(), group.model.context()), group.model.domain());
- return dataset.read_slice(self.fields_keys.concat(['__last_update']), { 'limit': self.limit })
- .then(function (records) {
+ if (group.attributes.length >= 1) {
+ def = dataset.read_slice(self.fields_keys.concat(['__last_update']), { 'limit': self.limit });
+ }
+ return def.then(function(records) {
self.nb_records += records.length;
self.dataset.ids.push.apply(self.dataset.ids, dataset.ids);
groups_array[index] = new instance.web_kanban.KanbanGroup(self, records, group, dataset);
diff --git a/debian/copyright b/debian/copyright
index f681d540a0a..e477adb524d 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -40,7 +40,7 @@ License: GPL-2+
.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.
On Debian systems, the complete text of the GNU General Public License
can be found in /usr/share/common-licenses/GPL-2 file.
@@ -93,7 +93,7 @@ License: LGPL-2.1
.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.
On Debian systems, the complete text of the GNU Library General Public License
can be found in /usr/share/common-licenses/LGPL-2.1 file.
@@ -137,7 +137,7 @@ License: GPL-2+
.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.
On Debian systems, the complete text of the GNU General Public License
can be found in /usr/share/common-licenses/GPL-2 file.
@@ -159,7 +159,7 @@ License: GPL-2+
.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
.
On Debian systems, the complete text of the GNU General Public License
can be found in /usr/share/common-licenses/GPL-2 file.
diff --git a/history/check_profile_l10n_all.py b/history/check_profile_l10n_all.py
index 5c1c1fa9bca..e7b391a942a 100644
--- a/history/check_profile_l10n_all.py
+++ b/history/check_profile_l10n_all.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#
diff --git a/history/gen_graph.sh b/history/gen_graph.sh
index b052528eef4..7be31ed8061 100755
--- a/history/gen_graph.sh
+++ b/history/gen_graph.sh
@@ -24,7 +24,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
##############################################################################
diff --git a/openerp-wsgi.py b/openerp-wsgi.py
index 9ae18ffc69e..90f43ddab21 100644
--- a/openerp-wsgi.py
+++ b/openerp-wsgi.py
@@ -1,4 +1,3 @@
-#!/usr/bin/python
# WSGI Handler sample configuration file.
#
# Change the appropriate settings below, in order to provide the parameters
diff --git a/openerp/addons/base/currency_data.xml b/openerp/addons/base/currency_data.xml
index 7173b8492ab..96ff81cc0d1 100644
--- a/openerp/addons/base/currency_data.xml
+++ b/openerp/addons/base/currency_data.xml
@@ -9,7 +9,6 @@
0.01
4
before
-
1.2834
@@ -23,7 +22,6 @@
Bs.F
0.0001
4
-
5.864
@@ -36,7 +34,6 @@
$
0.01
4
-
1.3388
@@ -50,7 +47,6 @@
CHF
0.01
4
-
1.3086
@@ -63,7 +59,6 @@
R$
0.01
4
-
2.2344
@@ -76,7 +71,6 @@
¥
0.01
4
-
8.7556
@@ -90,7 +84,6 @@
$
0.01
4
-
2933.8378
@@ -103,7 +96,6 @@
Kč
0.01
4
-
26.5634
@@ -116,7 +108,6 @@
kr
0.01
4
-
7.4445
@@ -130,7 +121,6 @@
Ft
0.01
4
-
271.5621
@@ -143,7 +133,6 @@
Rp
0.01
4
-
14352.00
@@ -161,7 +150,6 @@
Ls
0.01
4
-
0.7086
@@ -174,7 +162,6 @@
kr
0.01
4
-
7.8668
@@ -187,7 +174,6 @@
XPF
1.00
4
-
119.331742
@@ -200,7 +186,6 @@
B/.
0.01
4
-
1.2676
@@ -213,7 +198,6 @@
zł
0.01
4
-
4.1005
@@ -226,7 +210,6 @@
kr
0.01
4
-
10.3004
@@ -239,7 +222,6 @@
$
0.01
4
-
5.0881
@@ -252,7 +234,6 @@
₹
0.01
4
-
59.9739
@@ -265,7 +246,6 @@
$
0.01
4
-
1.4070
@@ -278,7 +258,6 @@
₴
0.01
4
-
10.1969
@@ -291,7 +270,6 @@
₫
0.01
4
-
26330.01
@@ -304,7 +282,6 @@
$
0.01
4
-
11.1608
@@ -317,7 +294,6 @@
¥
0.01
4
-
133.62
@@ -330,7 +306,6 @@
лв
0.01
4
-
1.9558
@@ -343,7 +318,6 @@
Lt
0.01
4
-
3.4528
@@ -356,7 +330,6 @@
lei
0.01
4
-
4.2253
@@ -369,7 +342,6 @@
kn
0.01
4
-
7.2936
@@ -382,7 +354,6 @@
руб
0.01
4
-
43.16
@@ -395,7 +366,6 @@
TL
0.01
4
-
2.1411
@@ -408,7 +378,6 @@
₩
0.01
4
-
1662.37
@@ -421,7 +390,6 @@
$
0.01
4
-
18.6664
@@ -434,7 +402,6 @@
RM
0.01
4
-
4.8887
@@ -447,7 +414,6 @@
$
0.01
4
-
1.9764
@@ -460,7 +426,6 @@
Php
0.01
4
-
66.1
@@ -473,7 +438,6 @@
$
0.01
4
-
2.0126
@@ -486,7 +450,6 @@
R
0.01
4
-
10.5618
@@ -515,7 +478,6 @@
Rs
0.01
4
-
40.28
@@ -528,7 +490,6 @@
CFA
1
4
-
655.957
@@ -541,7 +502,6 @@
FCFA
1
4
-
655.957
@@ -554,7 +514,6 @@
USh
1
4
-
3401.91388
@@ -567,7 +526,6 @@
L
0.01
4
-
25
@@ -580,7 +538,6 @@
$
0.01
4
-
710
@@ -593,7 +550,6 @@
$
0.01
4
-
@@ -606,7 +562,6 @@
Afs
0.01
4
-
@@ -619,7 +574,6 @@
Kz
0.01
4
-
@@ -632,7 +586,6 @@
$
0.01
4
-
@@ -645,7 +598,6 @@
դր.
0.01
4
-
@@ -658,7 +610,6 @@
Afl.
0.01
4
-
@@ -671,7 +622,6 @@
m
0.01
4
-
@@ -684,7 +634,6 @@
B$
0.01
4
-
@@ -697,7 +646,6 @@
BD
0.01
4
-
@@ -710,7 +658,6 @@
৳
0.01
4
-
@@ -723,7 +670,6 @@
Bds$
0.01
4
-
@@ -736,7 +682,6 @@
BR
0.01
4
-
@@ -749,7 +694,6 @@
BZ$
0.01
4
-
@@ -762,7 +706,6 @@
BD$
0.01
4
-
@@ -775,7 +718,6 @@
Nu.
0.01
4
-
@@ -788,7 +730,6 @@
Bs.
0.01
4
-
@@ -801,7 +742,6 @@
KM
0.01
4
-
@@ -814,7 +754,6 @@
P
0.01
4
-
@@ -827,7 +766,6 @@
FBu
0.01
4
-
@@ -840,7 +778,6 @@
៛
0.01
4
-
@@ -853,7 +790,6 @@
$
0.01
4
-
@@ -866,7 +802,6 @@
CF
0.01
4
-
@@ -879,7 +814,6 @@
Fr
0.01
4
-
@@ -892,7 +826,6 @@
$
0.01
4
-
@@ -905,7 +838,6 @@
ƒ
0.01
4
-
@@ -918,7 +850,6 @@
£
0.01
4
-
@@ -931,7 +862,6 @@
Fdj
0.01
4
-
@@ -944,7 +874,6 @@
RD$
0.01
4
-
@@ -957,7 +886,6 @@
TPE
0.01
4
-
@@ -970,7 +898,6 @@
S/.
0.01
4
-
@@ -983,7 +910,6 @@
E£
0.01
4
-
@@ -996,7 +922,6 @@
¢
0.01
4
-
@@ -1009,7 +934,6 @@
Nfk
0.01
4
-
@@ -1022,7 +946,6 @@
kr
0.01
4
-
@@ -1035,7 +958,6 @@
Br
0.01
4
-
@@ -1048,7 +970,6 @@
£
0.01
4
-
@@ -1061,7 +982,6 @@
FJ$
0.01
4
-
@@ -1074,7 +994,6 @@
ლ
0.01
4
-
@@ -1087,7 +1006,6 @@
£
0.01
4
-
@@ -1100,7 +1018,6 @@
Q
0.01
4
-
@@ -1113,7 +1030,6 @@
FG
0.01
4
-
@@ -1125,7 +1041,6 @@
GWP
0.01
4
-
@@ -1138,7 +1053,6 @@
$
0.01
4
-
@@ -1151,7 +1065,6 @@
G
0.01
4
-
@@ -1164,7 +1077,6 @@
kr
0.01
4
-
@@ -1177,7 +1089,6 @@
﷼
0.01
4
-
@@ -1190,7 +1101,6 @@
ع.د
0.01
4
-
@@ -1203,7 +1113,6 @@
₪
0.01
4
-
@@ -1216,7 +1125,6 @@
$
0.01
4
-
@@ -1229,7 +1137,6 @@
د.ا
0.01
4
-
@@ -1242,7 +1149,6 @@
лв
0.01
4
-
@@ -1255,7 +1161,6 @@
KSh
0.01
4
-
@@ -1268,7 +1173,6 @@
د.ك
0.01
4
-
@@ -1281,7 +1185,6 @@
лв
0.01
4
-
@@ -1294,7 +1197,6 @@
₭
0.01
4
-
@@ -1307,7 +1209,6 @@
ل.ل
0.01
4
-
@@ -1320,7 +1221,6 @@
L
0.01
4
-
@@ -1333,7 +1233,6 @@
L$
0.01
4
-
@@ -1346,7 +1245,6 @@
ل.د
0.01
4
-
@@ -1359,7 +1257,6 @@
MOP$
0.01
4
-
@@ -1372,7 +1269,6 @@
ден
0.01
4
-
@@ -1385,7 +1281,6 @@
Ar
0.01
4
-
@@ -1398,7 +1293,6 @@
MK
0.01
4
-
@@ -1411,7 +1305,6 @@
.ރ
0.01
4
-
@@ -1424,7 +1317,6 @@
UM
0.01
4
-
@@ -1437,7 +1329,6 @@
L
0.01
4
-
@@ -1450,7 +1341,6 @@
₮
0.01
4
-
@@ -1463,7 +1353,6 @@
د.م.
0.01
4
-
@@ -1476,7 +1365,6 @@
$
0.01
4
-
@@ -1489,7 +1377,6 @@
DZ
0.01
4
-
@@ -1502,7 +1389,6 @@
GH¢
0.01
4
-
@@ -1515,7 +1401,6 @@
D
0.01
4
-
@@ -1528,7 +1413,6 @@
Ƶ
0.01
4
-
@@ -1541,7 +1425,6 @@
MT
0.01
4
-
@@ -1554,7 +1437,6 @@
K
0.01
4
-
@@ -1567,7 +1449,6 @@
$
0.01
4
-
@@ -1580,7 +1461,6 @@
₨
0.01
4
-
@@ -1593,7 +1473,6 @@
L
0.01
4
-
@@ -1606,7 +1485,6 @@
C$
0.01
4
-
@@ -1619,7 +1497,6 @@
₦
0.01
4
-
@@ -1632,7 +1509,6 @@
₩
0.01
4
-
@@ -1645,7 +1521,6 @@
Z$
0.01
4
-
@@ -1658,7 +1533,6 @@
ZK
0.01
4
-
@@ -1671,7 +1545,6 @@
﷼
0.01
4
-
@@ -1684,7 +1557,6 @@
Bs
0.01
4
-
@@ -1697,7 +1569,6 @@
€
0.01
4
-
@@ -1710,7 +1581,6 @@
VT
0.01
4
-
@@ -1723,7 +1593,6 @@
лв
0.01
4
-
@@ -1736,7 +1605,6 @@
$U
0.01
4
-
@@ -1749,7 +1617,6 @@
د.إ
0.01
4
-
@@ -1762,7 +1629,6 @@
₴
0.01
4
-
@@ -1775,7 +1641,6 @@
m
0.01
4
-
@@ -1788,7 +1653,6 @@
TL
0.01
4
-
@@ -1801,7 +1665,6 @@
DT
0.01
4
-
@@ -1814,7 +1677,6 @@
$
0.01
4
-
@@ -1827,7 +1689,6 @@
T$
0.01
4
-
@@ -1840,7 +1701,6 @@
฿
0.01
4
-
@@ -1853,7 +1713,6 @@
x/y
0.01
4
-
@@ -1865,7 +1724,6 @@
TJR
0.01
4
-
@@ -1878,7 +1736,6 @@
NT$
0.01
4
-
@@ -1891,7 +1748,6 @@
£
0.01
4
-
@@ -1904,7 +1760,6 @@
E
0.01
4
-
@@ -1917,7 +1772,6 @@
$
0.01
4
-
@@ -1930,7 +1784,6 @@
£Sd
0.01
4
-
@@ -1943,7 +1796,6 @@
Rs
0.01
4
-
@@ -1956,7 +1808,6 @@
£
0.01
4
-
@@ -1970,7 +1821,6 @@
0.01
4
before
-
@@ -1983,7 +1833,6 @@
Sh.
0.01
4
-
@@ -1996,7 +1845,6 @@
SI$
0.01
4
-
@@ -2009,7 +1857,6 @@
Le
0.01
4
-
@@ -2022,7 +1869,6 @@
SR
0.01
4
-
@@ -2035,7 +1881,6 @@
din.
0.01
4
-
@@ -2048,7 +1893,6 @@
SR
0.01
4
-
@@ -2061,7 +1905,6 @@
Db
0.01
4
-
@@ -2074,7 +1917,6 @@
₤
0.01
4
-
@@ -2087,7 +1929,6 @@
WS$
0.01
4
-
@@ -2100,7 +1941,6 @@
£
0.01
4
-
@@ -2113,7 +1953,6 @@
RF
0.01
4
-
@@ -2126,7 +1965,6 @@
R
0.01
4
-
@@ -2139,7 +1977,6 @@
L
0.01
4
-
@@ -2152,7 +1989,6 @@
QR
0.01
4
-
@@ -2165,7 +2001,6 @@
zł
0.01
4
-
@@ -2178,7 +2013,6 @@
S/.
0.01
4
-
@@ -2191,7 +2025,6 @@
₲
0.01
4
-
@@ -2204,7 +2037,6 @@
K
0.01
4
-
@@ -2217,7 +2049,6 @@
Rs.
0.01
4
-
@@ -2230,7 +2061,6 @@
ر.ع.
0.01
4
-
@@ -2243,7 +2073,6 @@
$
0.01
4
-
@@ -2256,7 +2085,6 @@
Sk
0.01
4
-
@@ -2268,7 +2096,6 @@
SIT
0.01
4
-
@@ -2281,7 +2108,6 @@
дин.
0.01
4
-
diff --git a/openerp/addons/base/ir/ir_attachment.py b/openerp/addons/base/ir/ir_attachment.py
index b4cb3a8c2cb..f00cc3f85ed 100644
--- a/openerp/addons/base/ir/ir_attachment.py
+++ b/openerp/addons/base/ir/ir_attachment.py
@@ -198,7 +198,7 @@ class ir_attachment(osv.osv):
continue
res_ids.setdefault(rmod,set()).add(rid)
if values:
- if 'res_model' in values and 'res_id' in values:
+ if values.get('res_model') and 'res_id' in values:
res_ids.setdefault(values['res_model'],set()).add(values['res_id'])
ima = self.pool.get('ir.model.access')
diff --git a/openerp/addons/base/ir/ir_mail_server.py b/openerp/addons/base/ir/ir_mail_server.py
index 0805a5f8891..79154a35f3b 100644
--- a/openerp/addons/base/ir/ir_mail_server.py
+++ b/openerp/addons/base/ir/ir_mail_server.py
@@ -31,6 +31,7 @@ import re
import smtplib
import threading
+from openerp import SUPERUSER_ID
from openerp.osv import osv, fields
from openerp.tools.translate import _
from openerp.tools import html2text
@@ -419,11 +420,11 @@ class ir_mail_server(osv.osv):
# Get SMTP Server Details from Mail Server
mail_server = None
if mail_server_id:
- mail_server = self.browse(cr, uid, mail_server_id)
+ mail_server = self.browse(cr, SUPERUSER_ID, mail_server_id)
elif not smtp_server:
- mail_server_ids = self.search(cr, uid, [], order='sequence', limit=1)
+ mail_server_ids = self.search(cr, SUPERUSER_ID, [], order='sequence', limit=1)
if mail_server_ids:
- mail_server = self.browse(cr, uid, mail_server_ids[0])
+ mail_server = self.browse(cr, SUPERUSER_ID, mail_server_ids[0])
if mail_server:
smtp_server = mail_server.smtp_host
diff --git a/openerp/addons/base/ir/ir_sequence.py b/openerp/addons/base/ir/ir_sequence.py
index 44c9e57af32..0f505814c0c 100644
--- a/openerp/addons/base/ir/ir_sequence.py
+++ b/openerp/addons/base/ir/ir_sequence.py
@@ -54,6 +54,34 @@ class ir_sequence(openerp.osv.osv.osv):
"""
_name = 'ir.sequence'
_order = 'name'
+
+ def _get_number_next_actual(self, cr, user, ids, field_name, arg, context=None):
+ '''Return number from ir_sequence row when no_gap implementation,
+ and number from postgres sequence when standard implementation.'''
+ res = dict.fromkeys(ids)
+ for element in self.browse(cr, user, ids, context=context):
+ if element.implementation != 'standard':
+ res[element.id] = element.number_next
+ else:
+ # get number from postgres sequence. Cannot use
+ # currval, because that might give an error when
+ # not having used nextval before.
+ statement = (
+ "SELECT last_value, increment_by, is_called"
+ " FROM ir_sequence_%03d"
+ % element.id)
+ cr.execute(statement)
+ (last_value, increment_by, is_called) = cr.fetchone()
+ if is_called:
+ res[element.id] = last_value + increment_by
+ else:
+ res[element.id] = last_value
+ return res
+
+ def _set_number_next_actual(self, cr, uid, id, name, value, args=None, context=None):
+ return self.write(cr, uid, id, {'number_next': value or 0}, context=context)
+
+
_columns = {
'name': openerp.osv.fields.char('Name', size=64, required=True),
'code': openerp.osv.fields.selection(_code_get, 'Code', size=64),
@@ -67,6 +95,7 @@ class ir_sequence(openerp.osv.osv.osv):
'prefix': openerp.osv.fields.char('Prefix', size=64, help="Prefix value of the record for the sequence"),
'suffix': openerp.osv.fields.char('Suffix', size=64, help="Suffix value of the record for the sequence"),
'number_next': openerp.osv.fields.integer('Next Number', required=True, help="Next number of this sequence"),
+ 'number_next_actual': openerp.osv.fields.function(_get_number_next_actual, fnct_inv=_set_number_next_actual, type='integer', required=True, string='Next Number', help='Next number that will be used. This number can be incremented frequently so the displayed value might already be obsolete'),
'number_increment': openerp.osv.fields.integer('Increment Number', required=True, help="The next number of the sequence will be incremented by this number"),
'padding' : openerp.osv.fields.integer('Number Padding', required=True, help="OpenERP will automatically adds some '0' on the left of the 'Next Number' to get the required padding size."),
'company_id': openerp.osv.fields.many2one('res.company', 'Company'),
@@ -77,6 +106,7 @@ class ir_sequence(openerp.osv.osv.osv):
'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'ir.sequence', context=c),
'number_increment': 1,
'number_next': 1,
+ 'number_next_actual': 1,
'padding' : 0,
}
@@ -121,7 +151,7 @@ class ir_sequence(openerp.osv.osv.osv):
# object depends on it.
cr.execute("DROP SEQUENCE IF EXISTS %s RESTRICT " % names)
- def _alter_sequence(self, cr, id, number_increment, number_next):
+ def _alter_sequence(self, cr, id, number_increment, number_next=None):
""" Alter a PostreSQL sequence.
There is no access rights check.
@@ -129,9 +159,15 @@ class ir_sequence(openerp.osv.osv.osv):
if number_increment == 0:
raise osv.except_osv(_('Warning!'),_("Increment number must not be zero."))
assert isinstance(id, (int, long))
- cr.execute("""
- ALTER SEQUENCE ir_sequence_%03d INCREMENT BY %%s RESTART WITH %%s
- """ % id, (number_increment, number_next))
+ seq_name = 'ir_sequence_%03d' % (id,)
+ cr.execute("SELECT relname FROM pg_class WHERE relkind = %s AND relname=%s", ('S', seq_name))
+ if not cr.fetchone():
+ # sequence is not created yet, we're inside create() so ignore it, will be set later
+ return
+ statement = "ALTER SEQUENCE %s INCREMENT BY %d" % (seq_name, number_increment)
+ if number_next is not None:
+ statement += " RESTART WITH %d" % (number_next, )
+ cr.execute(statement)
def create(self, cr, uid, values, context=None):
""" Create a sequence, in implementation == standard a fast gaps-allowed PostgreSQL sequence is used.
@@ -160,7 +196,13 @@ class ir_sequence(openerp.osv.osv.osv):
n = values.get('number_next', row['number_next'])
if row['implementation'] == 'standard':
if new_implementation in ('standard', None):
- self._alter_sequence(cr, row['id'], i, n)
+ # Implementation has NOT changed.
+ # Only change sequence if really requested.
+ if row['number_next'] != n:
+ self._alter_sequence(cr, row['id'], i, n)
+ else:
+ # Just in case only increment changed
+ self._alter_sequence(cr, row['id'], i)
else:
self._drop_sequence(cr, row['id'])
else:
@@ -200,7 +242,7 @@ class ir_sequence(openerp.osv.osv.osv):
force_company = context.get('force_company')
if not force_company:
force_company = self.pool.get('res.users').browse(cr, uid, uid).company_id.id
- sequences = self.read(cr, uid, seq_ids, ['company_id','implementation','number_next','prefix','suffix','padding'])
+ sequences = self.read(cr, uid, seq_ids, ['name','company_id','implementation','number_next','prefix','suffix','padding'])
preferred_sequences = [s for s in sequences if s['company_id'] and s['company_id'][0] == force_company ]
seq = preferred_sequences[0] if preferred_sequences else sequences[0]
if seq['implementation'] == 'standard':
@@ -210,8 +252,11 @@ class ir_sequence(openerp.osv.osv.osv):
cr.execute("SELECT number_next FROM ir_sequence WHERE id=%s FOR UPDATE NOWAIT", (seq['id'],))
cr.execute("UPDATE ir_sequence SET number_next=number_next+number_increment WHERE id=%s ", (seq['id'],))
d = self._interpolation_dict()
- interpolated_prefix = self._interpolate(seq['prefix'], d)
- interpolated_suffix = self._interpolate(seq['suffix'], d)
+ try:
+ interpolated_prefix = self._interpolate(seq['prefix'], d)
+ interpolated_suffix = self._interpolate(seq['suffix'], d)
+ except ValueError:
+ raise osv.except_osv(_('Warning'), _('Invalid prefix or suffix for sequence \'%s\'') % (seq.get('name')))
return interpolated_prefix + '%%0%sd' % seq['padding'] % seq['number_next'] + interpolated_suffix
def next_by_id(self, cr, uid, sequence_id, context=None):
diff --git a/openerp/addons/base/ir/ir_sequence_view.xml b/openerp/addons/base/ir/ir_sequence_view.xml
index 0fa46d61957..050eb9e2333 100644
--- a/openerp/addons/base/ir/ir_sequence_view.xml
+++ b/openerp/addons/base/ir/ir_sequence_view.xml
@@ -20,7 +20,7 @@
-
+
@@ -57,7 +57,7 @@
-
+
diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py
index 40b3b021751..02dfefe1e38 100644
--- a/openerp/addons/base/res/res_company.py
+++ b/openerp/addons/base/res/res_company.py
@@ -278,6 +278,10 @@ class res_company(osv.osv):
+
+
+
+
@@ -287,6 +291,9 @@ class res_company(osv.osv):
[[ company.partner_id.name ]]
%s
+
+
+
"""
@@ -310,13 +317,16 @@ class res_company(osv.osv):
-
-
+
+
+
+
+
+
[[ company.logo or removeParentNode('image') ]]
-
diff --git a/openerp/addons/base/res/res_currency.py b/openerp/addons/base/res/res_currency.py
index 70bc8299dbe..efe33f32fd9 100644
--- a/openerp/addons/base/res/res_currency.py
+++ b/openerp/addons/base/res/res_currency.py
@@ -77,6 +77,7 @@ class res_currency(osv.osv):
'position' : 'after',
'rounding': 0.01,
'accuracy': 4,
+ 'company_id': False,
}
_sql_constraints = [
# this constraint does not cover all cases due to SQL NULL handling for company_id,
diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py
index 01108939195..89b9448290e 100644
--- a/openerp/addons/base/res/res_partner.py
+++ b/openerp/addons/base/res/res_partner.py
@@ -74,7 +74,8 @@ class format_address(object):
def _tz_get(self,cr,uid, context=None):
- return [(x, x) for x in pytz.all_timezones]
+ # put POSIX 'Etc/*' entries at the end to avoid confusing users - see bug 1086728
+ return [(tz,tz) for tz in sorted(pytz.all_timezones, key=lambda tz: tz if not tz.startswith('Etc/') else '_')]
class res_partner_category(osv.osv):
diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py
index 4f76db03e82..72d9269487b 100644
--- a/openerp/addons/base/res/res_users.py
+++ b/openerp/addons/base/res/res_users.py
@@ -38,6 +38,7 @@ class groups(osv.osv):
_name = "res.groups"
_description = "Access Groups"
_rec_name = 'full_name'
+ _order = 'name'
def _get_full_name(self, cr, uid, ids, field, arg, context=None):
res = {}
diff --git a/openerp/addons/base/security/base_security.xml b/openerp/addons/base/security/base_security.xml
index b0de06078af..4bd78e353cf 100644
--- a/openerp/addons/base/security/base_security.xml
+++ b/openerp/addons/base/security/base_security.xml
@@ -87,6 +87,12 @@
['|','|',('company_id.child_ids','child_of',[user.company_id.id]),('company_id','child_of',[user.company_id.id]),('company_id','=',False)]
+
+ multi-company currency rule
+
+ ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]
+
+
diff --git a/openerp/addons/base/security/ir.model.access.csv b/openerp/addons/base/security/ir.model.access.csv
index 35d5b82bc41..e3198abb8fa 100644
--- a/openerp/addons/base/security/ir.model.access.csv
+++ b/openerp/addons/base/security/ir.model.access.csv
@@ -114,7 +114,7 @@
"access_ir_filter employee","ir_filters employee","model_ir_filters","group_user",1,1,1,1
"access_ir_filters","ir_filters_all","model_ir_filters",,1,1,1,1
"access_ir_config_parameter","ir_config_parameter","model_ir_config_parameter",,1,0,0,0
-"access_ir_mail_server_all","ir_mail_server","model_ir_mail_server",,1,0,0,0
+"access_ir_mail_server","ir_mail_server","model_ir_mail_server","group_system",1,1,1,1
"access_ir_actions_client","ir_actions_client all","model_ir_actions_client",,1,0,0,0
"access_ir_needaction_mixin","ir_needaction_mixin","model_ir_needaction_mixin",,1,1,1,1
diff --git a/openerp/addons/base/test/test_osv_expression.yml b/openerp/addons/base/test/test_osv_expression.yml
index f1610e8b3a4..1516f090e94 100644
--- a/openerp/addons/base/test/test_osv_expression.yml
+++ b/openerp/addons/base/test/test_osv_expression.yml
@@ -291,22 +291,22 @@
assert res_101 == [], 'res_101: expected %r, got %r' % ([], res_101)
assert res_102 == company_ids, 'res_102: expected %r, got %r' % (company_ids, res_102)
-
- Property of the query (one2many != False).
+ Verify domain evaluation for `one2many != False`
-
- !python {model: res.currency }: |
- ids = self.search(cr, uid, [])
- referenced_companies = set([x.company_id.id for x in self.browse(cr, uid, ids)])
- companies = set(self.pool.get('res.company').search(cr, uid, [('currency_ids', '!=', False)]))
- assert referenced_companies == companies
+ !python {model: res.partner.category }: |
+ all_ids = self.search(cr, uid, [])
+ parent_categs = set([c.parent_id.id for c in self.browse(cr, uid, all_ids) if c.parent_id])
+ result = set(self.search(cr, uid, [('child_ids', '!=', False)]))
+ assert result and result == parent_categs, "Got %r, expected %r" % (result, parent_categs)
-
- Property of the query (one2many = False).
+ Verify domain evaluation for `one2many == False`
-
- !python {model: res.currency }: |
- ids = self.search(cr, uid, [])
- referenced_companies = set([x.company_id.id for x in self.browse(cr, uid, ids)])
- unreferenced_companies = set(self.pool.get('res.company').search(cr, uid, [])).difference(referenced_companies)
- companies = set(self.pool.get('res.company').search(cr, uid, [('currency_ids', '=', False)]))
- assert unreferenced_companies == companies
+ !python {model: res.partner.category }: |
+ all_ids = self.search(cr, uid, [])
+ parent_categs = set([c.parent_id.id for c in self.browse(cr, uid, all_ids) if c.parent_id])
+ leaf_categs = set(all_ids) - parent_categs
+ result = set(self.search(cr, uid, [('child_ids', '=', False)]))
+ assert result and result == leaf_categs, "Got %r, expected %r" % (result, leaf_categs)
-
Equivalent queries.
-
diff --git a/openerp/cli/server.py b/openerp/cli/server.py
index 0315468b7b2..2ee9e53b3ca 100644
--- a/openerp/cli/server.py
+++ b/openerp/cli/server.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#
diff --git a/openerp/netsvc.py b/openerp/netsvc.py
index 626d983a221..755f6513b25 100644
--- a/openerp/netsvc.py
+++ b/openerp/netsvc.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#
diff --git a/openerp/osv/expression.py b/openerp/osv/expression.py
index 55e286d33f2..ef02882422c 100644
--- a/openerp/osv/expression.py
+++ b/openerp/osv/expression.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#
diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py
index 03d6dddf973..f1c421af5c9 100644
--- a/openerp/osv/orm.py
+++ b/openerp/osv/orm.py
@@ -3857,11 +3857,12 @@ class BaseModel(object):
# Attempt to distinguish record rule restriction vs deleted records,
# to provide a more specific error message - check if the missinf
cr.execute('SELECT id FROM ' + self._table + ' WHERE id IN %s', (tuple(missing_ids),))
- if cr.rowcount:
+ forbidden_ids = [x[0] for x in cr.fetchall()]
+ if forbidden_ids:
# the missing ids are (at least partially) hidden by access rules
if uid == SUPERUSER_ID:
return
- _logger.warning('Access Denied by record rules for operation: %s, uid: %s, model: %s', operation, uid, self._name)
+ _logger.warning('Access Denied by record rules for operation: %s on record ids: %r, uid: %s, model: %s', operation, forbidden_ids, uid, self._name)
raise except_orm(_('Access Denied'),
_('The requested operation cannot be completed due to security restrictions. Please contact your system administrator.\n\n(Document type: %s, Operation: %s)') % \
(self._description, operation))
diff --git a/openerp/report/render/rml2html/rml2html.py b/openerp/report/render/rml2html/rml2html.py
index c80698150b8..9122d068e6e 100644
--- a/openerp/report/render/rml2html/rml2html.py
+++ b/openerp/report/render/rml2html/rml2html.py
@@ -16,7 +16,7 @@
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
##############################################################################
diff --git a/openerp/report/render/rml2html/utils.py b/openerp/report/render/rml2html/utils.py
index c40118477f8..7c81a65a4e8 100644
--- a/openerp/report/render/rml2html/utils.py
+++ b/openerp/report/render/rml2html/utils.py
@@ -16,7 +16,7 @@
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
##############################################################################
diff --git a/openerp/report/render/rml2pdf/customfonts.py b/openerp/report/render/rml2pdf/customfonts.py
index 0c0095b8818..85874f2b82f 100644
--- a/openerp/report/render/rml2pdf/customfonts.py
+++ b/openerp/report/render/rml2pdf/customfonts.py
@@ -3,7 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 P. Christeas, Tiny SPRL ().
-# Copyright (C) 2010 OpenERP SA. (http://www.openerp.com)
+# Copyright (C) 2010-2013 OpenERP SA. (http://www.openerp.com)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -56,7 +56,11 @@ CustomTTFonts = [ ('Helvetica',"DejaVu Sans", "DejaVuSans.ttf", 'normal'),
('Courier',"FreeMono", "FreeMono.ttf", 'normal'),
('Courier',"FreeMono Bold", "FreeMonoBold.ttf", 'bold'),
('Courier',"FreeMono Oblique", "FreeMonoOblique.ttf", 'italic'),
- ('Courier',"FreeMono BoldOblique", "FreeMonoBoldOblique.ttf", 'bolditalic'),]
+ ('Courier',"FreeMono BoldOblique", "FreeMonoBoldOblique.ttf", 'bolditalic'),
+
+ # Sun-ExtA can be downloaded from http://okuc.net/SunWb/
+ ('Sun-ExtA',"Sun-ExtA", "Sun-ExtA.ttf", 'normal'),
+]
TTFSearchPath_Linux = [
diff --git a/openerp/report/render/rml2pdf/trml2pdf.py b/openerp/report/render/rml2pdf/trml2pdf.py
index e8d6375c98e..243cc02a0b3 100644
--- a/openerp/report/render/rml2pdf/trml2pdf.py
+++ b/openerp/report/render/rml2pdf/trml2pdf.py
@@ -160,9 +160,11 @@ class _rml_styles(object,):
for style in node.findall('paraStyle'):
sname = style.get('name')
self.styles[sname] = self._para_style_update(style)
-
- self.styles_obj[sname] = reportlab.lib.styles.ParagraphStyle(sname, self.default_style["Normal"], **self.styles[sname])
-
+ if sname in self.default_style:
+ for key, value in self.styles[sname].items():
+ setattr(self.default_style[sname], key, value)
+ else:
+ self.styles_obj[sname] = reportlab.lib.styles.ParagraphStyle(sname, self.default_style["Normal"], **self.styles[sname])
for variable in node.findall('initialize'):
for name in variable.findall('name'):
self.names[ name.get('id')] = name.get('value')
@@ -269,6 +271,7 @@ class _rml_doc(object):
from reportlab.pdfbase.ttfonts import TTFont
for node in els:
+
for font in node.findall('registerFont'):
name = font.get('fontName').encode('ascii')
fname = font.get('fontFile').encode('ascii')
diff --git a/openerp/report/render/rml2pdf/utils.py b/openerp/report/render/rml2pdf/utils.py
index adca350c8d0..ae70cd46c94 100644
--- a/openerp/report/render/rml2pdf/utils.py
+++ b/openerp/report/render/rml2pdf/utils.py
@@ -16,7 +16,7 @@
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
##############################################################################
diff --git a/openerp/service/cron.py b/openerp/service/cron.py
index fe57aa7186c..f21b27f7fea 100644
--- a/openerp/service/cron.py
+++ b/openerp/service/cron.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#
diff --git a/openerp/service/http_server.py b/openerp/service/http_server.py
index 63e8ce8338e..e25e75dba62 100644
--- a/openerp/service/http_server.py
+++ b/openerp/service/http_server.py
@@ -23,7 +23,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
###############################################################################
diff --git a/openerp/service/websrv_lib.py b/openerp/service/websrv_lib.py
index 7767cff2b30..9aeeff38828 100644
--- a/openerp/service/websrv_lib.py
+++ b/openerp/service/websrv_lib.py
@@ -21,7 +21,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
###############################################################################
diff --git a/openerp/service/workers.py b/openerp/service/workers.py
index 4106b69a632..9a6485b8fd3 100644
--- a/openerp/service/workers.py
+++ b/openerp/service/workers.py
@@ -353,6 +353,7 @@ class WorkerHTTP(Worker):
def start(self):
Worker.start(self)
+ self.multi.long_polling_socket.close()
self.server = WorkerBaseWSGIServer(self.multi.app)
class WorkerLongPolling(Worker):
@@ -362,6 +363,15 @@ class WorkerLongPolling(Worker):
# Disable the watchdog feature for this kind of worker.
self.watchdog_timeout = None
+ def watch_parent(self):
+ import gevent
+ while True:
+ if self.ppid != os.getppid():
+ _logger.info("WorkerLongPolling (%s) Parent changed", self.pid)
+ os.kill(os.getpid(), signal.SIGTERM)
+ return
+ gevent.sleep(self.multi.beat)
+
def start(self):
openerp.evented = True
_logger.info('Using gevent mode')
@@ -369,20 +379,22 @@ class WorkerLongPolling(Worker):
gevent.monkey.patch_all()
import gevent_psycopg2
gevent_psycopg2.monkey_patch()
+ from openerp.modules.registry import RegistryManager
+ from gevent.coros import RLock
+ RegistryManager.registries_lock = RLock()
Worker.start(self)
+ self.multi.socket.close()
+
+ import gevent
+ watcher = gevent.spawn(self.watch_parent)
+
+ log = _logger.getChild(self.__class__.__name__)
+ log.write = lambda msg: log.info(msg.strip())
+
from gevent.wsgi import WSGIServer
- self.server = WSGIServer(self.multi.long_polling_socket, self.multi.app)
- self.server.start()
-
- def stop(self):
- self.server.stop()
-
- def sleep(self):
- time.sleep(1)
-
- def process_work(self):
- pass
+ self.server = WSGIServer(self.multi.long_polling_socket, self.multi.app, log=log)
+ self.server.serve_forever()
class WorkerBaseWSGIServer(werkzeug.serving.BaseWSGIServer):
""" werkzeug WSGI Server patched to allow using an external listen socket
@@ -456,6 +468,8 @@ class WorkerCron(Worker):
def start(self):
Worker.start(self)
+ self.multi.socket.close()
+ self.multi.long_polling_socket.close()
openerp.service.start_internal()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/tests/test_mail.py b/openerp/tests/test_mail.py
old mode 100644
new mode 100755
diff --git a/setup.nsi b/setup.nsi
index 653a8798bb2..859ebdb39e2 100644
--- a/setup.nsi
+++ b/setup.nsi
@@ -21,7 +21,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#####################################################################################
!include 'MUI2.nsh'
diff --git a/setup.py b/setup.py
old mode 100755
new mode 100644
index 9f27e20a049..ff801a97933
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: utf-8 -*-
##############################################################################
#