diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py
index 9b18e1f3d24..1f5fcc58ccf 100644
--- a/addons/base_action_rule/base_action_rule.py
+++ b/addons/base_action_rule/base_action_rule.py
@@ -156,13 +156,13 @@ class base_action_rule(osv.osv):
""" Return a wrapper around `old_create` calling both `old_create` and
`_process`, in that order.
"""
- def create(cr, uid, vals, context=None):
+ def create(cr, uid, vals, context=None, **kwargs):
# avoid loops or cascading actions
if context and context.get('action'):
return old_create(cr, uid, vals, context=context)
context = dict(context or {}, action=True)
- new_id = old_create(cr, uid, vals, context=context)
+ new_id = old_create(cr, uid, vals, context=context, **kwargs)
# retrieve the action rules to run on creation
action_dom = [('model', '=', model), ('kind', 'in', ['on_create', 'on_create_or_write'])]
@@ -180,10 +180,10 @@ class base_action_rule(osv.osv):
""" Return a wrapper around `old_write` calling both `old_write` and
`_process`, in that order.
"""
- def write(cr, uid, ids, vals, context=None):
+ def write(cr, uid, ids, vals, context=None, **kwargs):
# avoid loops or cascading actions
if context and context.get('action'):
- return old_write(cr, uid, ids, vals, context=context)
+ return old_write(cr, uid, ids, vals, context=context, **kwargs)
context = dict(context or {}, action=True)
ids = [ids] if isinstance(ids, (int, long, str)) else ids
@@ -199,7 +199,7 @@ class base_action_rule(osv.osv):
pre_ids[action] = self._filter(cr, uid, action, action.filter_pre_id, ids, context=context)
# execute write
- old_write(cr, uid, ids, vals, context=context)
+ old_write(cr, uid, ids, vals, context=context, **kwargs)
# check postconditions, and execute actions on the records that satisfy them
for action in actions:
diff --git a/addons/hr_recruitment/hr_recruitment_data.xml b/addons/hr_recruitment/hr_recruitment_data.xml
index fdf5735bf8d..aa08217c788 100644
--- a/addons/hr_recruitment/hr_recruitment_data.xml
+++ b/addons/hr_recruitment/hr_recruitment_data.xml
@@ -148,7 +148,7 @@
Applicant Created
hr.job
-
+
job_id
diff --git a/addons/hr_timesheet_sheet/static/src/js/timesheet.js b/addons/hr_timesheet_sheet/static/src/js/timesheet.js
index c7afd62c8ab..ef1e2f17145 100644
--- a/addons/hr_timesheet_sheet/static/src/js/timesheet.js
+++ b/addons/hr_timesheet_sheet/static/src/js/timesheet.js
@@ -7,6 +7,9 @@ openerp.hr_timesheet_sheet = function(instance) {
events: {
"click .oe_timesheet_weekly_account a": "go_to",
},
+ ignore_fields: function() {
+ return ['line_id'];
+ },
init: function() {
this._super.apply(this, arguments);
var self = this;
@@ -323,11 +326,8 @@ openerp.hr_timesheet_sheet = function(instance) {
generate_o2m_value: function() {
var self = this;
var ops = [];
-
+ var ignored_fields = self.ignore_fields();
_.each(self.accounts, function(account) {
- var auth_keys = _.extend(_.clone(account.account_defaults), {
- name: true, amount:true, unit_amount: true, date: true, account_id:true,
- });
_.each(account.days, function(day) {
_.each(day.lines, function(line) {
if (line.unit_amount !== 0) {
@@ -338,12 +338,8 @@ openerp.hr_timesheet_sheet = function(instance) {
tmp[k] = v[0];
}
});
- // we have to remove some keys, because analytic lines are shitty
- _.each(_.keys(tmp), function(key) {
- if (auth_keys[key] === undefined) {
- tmp[key] = undefined;
- }
- });
+ // we remove line_id as the reference to the _inherits field will no longer exists
+ tmp = _.omit(tmp, ignored_fields);
ops.push(tmp);
}
});
diff --git a/addons/l10n_fr_hr_payroll/report/fiche_paye.py b/addons/l10n_fr_hr_payroll/report/fiche_paye.py
index c6933228687..18eb7f30b8a 100755
--- a/addons/l10n_fr_hr_payroll/report/fiche_paye.py
+++ b/addons/l10n_fr_hr_payroll/report/fiche_paye.py
@@ -31,6 +31,7 @@ class fiche_paye_parser(report_sxw.rml_parse):
def __init__(self, cr, uid, name, context):
super(fiche_paye_parser, self).__init__(cr, uid, name, context)
self.localcontext.update({
+ 'lang': "fr_FR",
'get_payslip_lines': self.get_payslip_lines,
'get_total_by_rule_category': self.get_total_by_rule_category,
'get_employer_line': self.get_employer_line,
diff --git a/addons/product/product_demo.xml b/addons/product/product_demo.xml
index 112cb581a4b..763c7620b13 100644
--- a/addons/product/product_demo.xml
+++ b/addons/product/product_demo.xml
@@ -135,11 +135,11 @@ HDD SH-1
Memory
- 16 Go
+ 16 GB
- 32 Go
+ 32 GB
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index fde10e27d88..10ca4d89f25 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -3337,6 +3337,7 @@ body.oe_single_form .oe_single_form_container {
background: white;
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
background-color: transparent;
+ z-index: 1800;
}
.tooltip .tooltip-inner {
text-align: left !important;
diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass
index 8c3e817db11..5aa1b2ebf50 100644
--- a/addons/web/static/src/css/base.sass
+++ b/addons/web/static/src/css/base.sass
@@ -2711,6 +2711,7 @@ body.oe_single_form
background: white
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5)
background-color: transparent
+ z-index: 1800
.tooltip-inner
text-align: left !important
max-width: 350px
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index f21cfbc1f84..9fcbdff1f89 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -183,6 +183,7 @@ instance.web.Dialog = instance.web.Widget.extend({
*/
close: function(reason) {
if (this.dialog_inited && !this.__tmp_dialog_hiding) {
+ $('.tooltip').remove(); //remove open tooltip if any to prevent them staying when modal has disappeared
this.trigger("closing", reason);
if (this.$el.is(":data(bs.modal)")) { // may have been destroyed by closing signal
this.__tmp_dialog_hiding = true;
diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js
index 29f6c3e4d9e..23645e22bf1 100644
--- a/addons/web/static/src/js/core.js
+++ b/addons/web/static/src/js/core.js
@@ -773,15 +773,18 @@ instance.web.unblockUI = function() {
$.fn.tooltip.Constructor.DEFAULTS.placement = 'auto top';
$.fn.tooltip.Constructor.DEFAULTS.html = true;
$.fn.tooltip.Constructor.DEFAULTS.container = 'body';
-//overwrite bootstrap tooltip method to fix bug when using placement
-//auto and the parent element does not exist anymore resulting in
-//an error. This should be remove once bootstrap fix the bug
+//overwrite bootstrap tooltip method to prevent showing 2 tooltip at the same time
var bootstrap_show_function = $.fn.tooltip.Constructor.prototype.show;
-$.fn.tooltip.Constructor.prototype.show = function (e) {
- if (this.$element.parent().length === 0){
- return;
- }
- return bootstrap_show_function.call(this, e);
+$.fn.tooltip.Constructor.prototype.show = function () {
+ $('.tooltip').remove();
+ //the following fix the bug when using placement
+ //auto and the parent element does not exist anymore resulting in
+ //an error. This should be remove once we updade bootstrap to a version that fix the bug
+ //edit: bug has been fixed here : https://github.com/twbs/bootstrap/pull/13752
+ var e = $.Event('show.bs.' + this.type);
+ var inDom = $.contains(document.documentElement, this.$element[0]);
+ if (e.isDefaultPrevented() || !inDom) return;
+ return bootstrap_show_function.call(this);
};
/**
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index 956ec494573..7372e8a3783 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -1869,25 +1869,9 @@ instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.Invi
do_attach_tooltip: function(widget, trigger, options) {
widget = widget || this;
trigger = trigger || this.$el;
- var container = 'body';
- /*TODO: need to be refactor
- in the case we can find the view form in the parent,
- attach the element to it (to prevent tooltip to keep showing
- when switching view) or if we have a modal currently showing,
- attach tooltip to the modal to prevent the tooltip to show in the body in the
- case we close the modal too fast*/
- if ($(trigger).parents('.oe_view_manager_view_form').length > 0){
- container = $(trigger).parents('.oe_view_manager_view_form');
- }
- else {
- if (window.$('.modal.in').length>0){
- container = window.$('.modal.in:last()');
- }
- }
options = _.extend({
delay: { show: 500, hide: 0 },
trigger: 'hover',
- container: container,
title: function() {
var template = widget.template + '.tooltip';
if (!QWeb.has_template(template)) {
@@ -2399,6 +2383,7 @@ instance.web.form.KanbanSelection = instance.web.form.FieldChar.extend({
if (li.length) {
var value = {};
value[self.name] = String(li.data('value'));
+ self.record_id = self.view.datarecord.id;
if (self.record_id) {
return self.view.dataset._model.call('write', [[self.record_id], value, self.view.dataset.get_context()]).done(self.reload_record.bind(self));
} else {
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index b4b42b122af..9a192e4db90 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -1611,6 +1611,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
.filter(function (column) { return column.tag === 'field';})
.pluck('name').value(),
function (groups) {
+ self.view.$pager.hide();
$el[0].appendChild(
self.render_groups(groups));
if (post_render) { post_render(); }
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index a9a444d0004..7b7da1dd744 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -617,7 +617,6 @@ instance.web.ViewManager = instance.web.Widget.extend({
var view_promise;
var form = this.views['form'];
if (!view || (form && form.controller && !form.controller.can_be_discarded())) {
- self.trigger('switch_mode', view_type, no_store, view_options);
return $.Deferred().reject();
}
if (!no_store) {
diff --git a/addons/web_calendar/static/src/js/web_calendar.js b/addons/web_calendar/static/src/js/web_calendar.js
index 3b87984de77..532dd4f05b6 100644
--- a/addons/web_calendar/static/src/js/web_calendar.js
+++ b/addons/web_calendar/static/src/js/web_calendar.js
@@ -610,13 +610,17 @@ openerp.web_calendar = function(instance) {
date_start_day = new Date(event.start.getFullYear(),event.start.getMonth(),event.start.getDate(),7);
date_stop_day = new Date(event_end.getFullYear(),event_end.getMonth(),event_end.getDate(),19);
}
+ data[this.date_start] = instance.web.parse_value(date_start_day, this.fields[this.date_start]);
+ if (this.date_stop) {
+ data[this.date_stop] = instance.web.parse_value(date_stop_day, this.fields[this.date_stop]);
+ }
diff_seconds = Math.round((date_stop_day.getTime() - date_start_day.getTime()) / 1000);
}
else {
- data[this.date_start] = event.start;
+ data[this.date_start] = instance.web.parse_value(event.start, this.fields[this.date_start]);
if (this.date_stop) {
- data[this.date_stop] = event_end;
+ data[this.date_stop] = instance.web.parse_value(event_end, this.fields[this.date_stop]);
}
diff_seconds = Math.round((event_end.getTime() - event.start.getTime()) / 1000);
}
diff --git a/addons/web_kanban/static/src/js/kanban.js b/addons/web_kanban/static/src/js/kanban.js
index 239a703d276..e6a4b0dd1eb 100644
--- a/addons/web_kanban/static/src/js/kanban.js
+++ b/addons/web_kanban/static/src/js/kanban.js
@@ -938,10 +938,6 @@ instance.web_kanban.KanbanRecord = instance.web.Widget.extend({
var self = this;
this.setup_color_picker();
this.$el.find('[title]').each(function(){
- //in case of kanban, attach tooltip to the element itself
- //otherwise it might stay on screen when kanban view reload
- //since default container is body.
- //(when clicking on ready for next stage for example)
$(this).tooltip({
delay: { show: 500, hide: 0},
container: $(this),
diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py
index d96da28e195..7dc3bb69d33 100644
--- a/addons/website/models/ir_http.py
+++ b/addons/website/models/ir_http.py
@@ -198,6 +198,11 @@ class ir_http(orm.AbstractModel):
if isinstance(exception.qweb.get('cause'), openerp.exceptions.AccessError):
code = 403
+ if isinstance(exception, werkzeug.exceptions.HTTPException) and code is None:
+ # Hand-crafted HTTPException likely coming from abort(),
+ # usually for a redirect response -> return it directly
+ return exception
+
if code == 500:
logger.error("500 Internal Server Error:\n\n%s", values['traceback'])
if 'qweb_exception' in values:
diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml
index 4a37ae180fc..128780ae9e0 100644
--- a/addons/website/views/website_templates.xml
+++ b/addons/website/views/website_templates.xml
@@ -114,8 +114,8 @@
-
-
+
+
diff --git a/addons/website_sale/static/src/js/website.tour.sale.js b/addons/website_sale/static/src/js/website.tour.sale.js
index 8867334f403..a2278a26ad4 100644
--- a/addons/website_sale/static/src/js/website.tour.sale.js
+++ b/addons/website_sale/static/src/js/website.tour.sale.js
@@ -12,13 +12,13 @@
element: '.oe_product_cart a:contains("iPod")',
},
{
- title: "select ipod 32Go",
+ title: "select ipod 32GB",
waitFor: '#product_detail',
- element: 'label:contains(32 Go) input',
+ element: 'label:contains(32 GB) input',
},
{
title: "click on add to cart",
- waitFor: 'label:contains(32 Go) input[checked]',
+ waitFor: 'label:contains(32 GB) input[checked]',
element: 'form[action="/shop/cart/update"] .btn',
},
{
@@ -29,11 +29,11 @@
{
title: "add one more iPod",
waitFor: '.my_cart_quantity:contains(2)',
- element: '#cart_products tr:contains("32 Go") a.js_add_cart_json:eq(1)',
+ element: '#cart_products tr:contains("32 GB") a.js_add_cart_json:eq(1)',
},
{
title: "remove Headphones",
- waitFor: '#cart_products tr:contains("32 Go") input.js_quantity[value=2]',
+ waitFor: '#cart_products tr:contains("32 GB") input.js_quantity[value=2]',
element: '#cart_products tr:contains("Apple In-Ear Headphones") a.js_add_cart_json:first',
},
{
diff --git a/openerp/modules/loading.py b/openerp/modules/loading.py
index 2b9fca6fca9..b8d52416514 100644
--- a/openerp/modules/loading.py
+++ b/openerp/modules/loading.py
@@ -215,7 +215,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
# Set new modules and dependencies
modobj.write(cr, SUPERUSER_ID, [module_id], {'state': 'installed', 'latest_version': ver})
# Update translations for all installed languages
- modobj.update_translations(cr, SUPERUSER_ID, [module_id], None)
+ modobj.update_translations(cr, SUPERUSER_ID, [module_id], None, {'overwrite': openerp.tools.config["overwrite_existing_translations"]})
package.state = 'installed'
for kind in ('init', 'demo', 'update'):
diff --git a/openerp/report/report_sxw.py b/openerp/report/report_sxw.py
index b4f90126b92..f98261b0833 100644
--- a/openerp/report/report_sxw.py
+++ b/openerp/report/report_sxw.py
@@ -241,8 +241,10 @@ class rml_parse(object):
def _get_lang_dict(self):
pool_lang = self.pool['res.lang']
lang = self.localcontext.get('lang', 'en_US') or 'en_US'
- lang_ids = pool_lang.search(self.cr,self.uid,[('code','=',lang)])[0]
- lang_obj = pool_lang.browse(self.cr,self.uid,lang_ids)
+ lang_ids = pool_lang.search(self.cr,self.uid,[('code','=',lang)])
+ if not lang_ids:
+ lang_ids = pool_lang.search(self.cr,self.uid,[('code','=','en_US')])
+ lang_obj = pool_lang.browse(self.cr,self.uid,lang_ids[0])
self.lang_dict.update({'lang_obj':lang_obj,'date_format':lang_obj.date_format,'time_format':lang_obj.time_format})
self.default_lang[lang] = self.lang_dict.copy()
return True
diff --git a/openerp/service/db.py b/openerp/service/db.py
index de083f5b8ed..33bfc910ebf 100644
--- a/openerp/service/db.py
+++ b/openerp/service/db.py
@@ -156,6 +156,24 @@ def exp_get_progress(id):
exc, tb = a['exception'], a['traceback']
raise Exception, exc, tb
+
+def _drop_conn(cr, db_name):
+ # Try to terminate all other connections that might prevent
+ # dropping the database
+ try:
+ # PostgreSQL 9.2 renamed pg_stat_activity.procpid to pid:
+ # http://www.postgresql.org/docs/9.2/static/release-9-2.html#AEN110389
+ pid_col = 'pid' if cr._cnx.server_version >= 90200 else 'procpid'
+
+ cr.execute("""SELECT pg_terminate_backend(%(pid_col)s)
+ FROM pg_stat_activity
+ WHERE datname = %%s AND
+ %(pid_col)s != pg_backend_pid()""" % {'pid_col': pid_col},
+ (db_name,))
+ except Exception:
+ pass
+
+
def exp_drop(db_name):
if db_name not in exp_list(True):
return False
@@ -164,21 +182,8 @@ def exp_drop(db_name):
db = openerp.sql_db.db_connect('postgres')
with closing(db.cursor()) as cr:
- cr.autocommit(True) # avoid transaction block
- # Try to terminate all other connections that might prevent
- # dropping the database
- try:
- # PostgreSQL 9.2 renamed pg_stat_activity.procpid to pid:
- # http://www.postgresql.org/docs/9.2/static/release-9-2.html#AEN110389
- pid_col = 'pid' if cr._cnx.server_version >= 90200 else 'procpid'
-
- cr.execute("""SELECT pg_terminate_backend(%(pid_col)s)
- FROM pg_stat_activity
- WHERE datname = %%s AND
- %(pid_col)s != pg_backend_pid()""" % {'pid_col': pid_col},
- (db_name,))
- except Exception:
- pass
+ cr.autocommit(True) # avoid transaction block
+ _drop_conn(cr, db_name)
try:
cr.execute('DROP DATABASE "%s"' % db_name)
@@ -335,6 +340,7 @@ def exp_rename(old_name, new_name):
db = openerp.sql_db.db_connect('postgres')
with closing(db.cursor()) as cr:
cr.autocommit(True) # avoid transaction block
+ _drop_conn(cr, old_name)
try:
cr.execute('ALTER DATABASE "%s" RENAME TO "%s"' % (old_name, new_name))
_logger.info('RENAME DB: %s -> %s', old_name, new_name)
diff --git a/openerp/tests/common.py b/openerp/tests/common.py
index 1d9841692e7..658ef89423d 100644
--- a/openerp/tests/common.py
+++ b/openerp/tests/common.py
@@ -16,6 +16,8 @@ import unittest2
import urllib2
import xmlrpclib
from datetime import datetime, timedelta
+from shutil import rmtree
+from tempfile import mkdtemp
import werkzeug
@@ -149,8 +151,10 @@ 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()
def tearDown(self):
+ rmtree(self.localstorage_path)
self.registry.leave_test_mode()
super(HttpCase, self).tearDown()
@@ -259,7 +263,11 @@ class HttpCase(TransactionCase):
phantomtest = os.path.join(os.path.dirname(__file__), 'phantomtest.js')
# phantom.args[0] == phantomtest path
# phantom.args[1] == options
- cmd = ['phantomjs', jsfile, phantomtest, json.dumps(options)]
+ cmd = [
+ 'phantomjs',
+ '--local-storage-path', self.localstorage_path,
+ jsfile, phantomtest, json.dumps(options)
+ ]
self.phantom_run(cmd, timeout)
def phantom_js(self, url_path, code, ready="window", login=None, timeout=60, **kw):