[MERGE] forward port of branch saas-2 up to revid 3865 chs@openerp.com-20131031111945-u3wi11e4rykpslme

bzr revid: chs@openerp.com-20131030183314-d75tbpxjjk3u79er
bzr revid: chs@openerp.com-20131031144026-09f3eqfwfj2bcefs
This commit is contained in:
Christophe Simonis 2013-10-31 15:40:26 +01:00
commit 88292396c7
5 changed files with 105 additions and 30 deletions

View File

@ -90,13 +90,16 @@ db_list = http.db_list
db_monodb = http.db_monodb
def redirect_with_hash(url, code=303):
redirect_code = "<html><head><script>window.location = '%s' + location.hash;</script></head></html>" % url
if request.httprequest.user_agent.browser == 'msie':
try:
version = float(request.httprequest.user_agent.version)
if version < 10:
return "<html><head><script>window.location = '%s#' + location.hash;</script></head></html>" % url
return redirect_code
except Exception:
pass
elif request.httprequest.user_agent.browser == 'safari':
return redirect_code
return werkzeug.utils.redirect(url, code)
def module_topological_sort(modules):
@ -534,14 +537,12 @@ class Home(http.Controller):
def web_client(self, s_action=None, db=None, debug=False, **kw):
debug = debug != False
try:
lst = http.db_list()
except openerp.exceptions.AccessDenied:
lst = []
lst = http.db_list(True)
if db not in lst:
db = None
guessed_db = http.db_monodb(request.httprequest)
if guessed_db is None and len(lst) > 0:
guessed_db = lst[0]
def redirect(db):
query = dict(urlparse.parse_qsl(request.httprequest.query_string, keep_blank_values=True))
@ -549,11 +550,8 @@ class Home(http.Controller):
redirect = request.httprequest.path + '?' + urllib.urlencode(query)
return redirect_with_hash(redirect)
if guessed_db is None and db is None and lst:
return redirect(lst[0])
if guessed_db is None and lst:
guessed_db = lst[0]
if db is None and guessed_db is not None:
return redirect(guessed_db)
if db is not None and db != guessed_db:
request.session.logout()

View File

@ -1292,7 +1292,7 @@ openerp.str_to_datetime = function(str) {
if ( !res ) {
throw new Error("'" + str + "' is not a valid datetime");
}
var tmp = new Date();
var tmp = new Date(0);
tmp.setUTCFullYear(parseFloat(res[1]));
tmp.setUTCMonth(parseFloat(res[2]) - 1);
tmp.setUTCDate(parseFloat(res[3]));
@ -1324,7 +1324,7 @@ openerp.str_to_date = function(str) {
if ( !res ) {
throw new Error("'" + str + "' is not a valid date");
}
var tmp = new Date();
var tmp = new Date(0);
tmp.setFullYear(parseFloat(res[1]));
tmp.setMonth(parseFloat(res[2]) - 1);
tmp.setDate(parseFloat(res[3]));
@ -1451,4 +1451,4 @@ if (typeof(define) !== "undefined") { // amd
window.openerp = declare($, _, QWeb2);
}
})();
})();

View File

@ -501,7 +501,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
*
* @returns {$.Deferred} promise to content reloading
*/
reload_content: function () {
reload_content: synchronized(function () {
var self = this;
self.$el.find('.oe_list_record_selector').prop('checked', false);
this.records.reset();
@ -525,7 +525,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
limit: this._limit
});
return reloaded.promise();
},
}),
reload: function () {
return this.reload_content();
},
@ -1367,6 +1367,9 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
.removeClass('ui-icon-triangle-1-s')
.addClass('ui-icon-triangle-1-e');
child.close();
// force recompute the selection as closing group reset properties
var selection = self.get_selection();
$(self).trigger('selected', [selection.ids, this.records]);
}
});
}
@ -1377,22 +1380,29 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
if (group.grouped_on) {
var row_data = {};
row_data[group.grouped_on] = group;
var group_label = _t("Undefined");
var group_column = _(self.columns).detect(function (column) {
return column.id === group.grouped_on; });
if (! group_column) {
throw new Error(_.str.sprintf(
_t("Grouping on field '%s' is not possible because that field does not appear in the list view."),
group.grouped_on));
}
var group_label;
try {
group_label = group_column.format(row_data, {
value_if_empty: _t("Undefined"),
process_modifiers: false
});
} catch (e) {
group_label = _.str.escapeHTML(row_data[group_column.id].value);
if (group_column) {
try {
group_label = group_column.format(row_data, {
value_if_empty: _t("Undefined"),
process_modifiers: false
});
} catch (e) {
group_label = _.str.escapeHTML(row_data[group_column.id].value);
}
} else {
group_label = group.value;
if (group_label instanceof Array) {
group_label = group_label[1];
}
if (group_label === false) {
group_label = _t('Undefined');
}
group_label = _.str.escapeHTML(group_label);
}
// group_label is html-clean (through format or explicit
// escaping if format failed), can inject straight into HTML
$group_column.html(_.str.sprintf(_t("%s (%d)"),
@ -1637,6 +1647,22 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
}
});
/**
* Serializes concurrent calls to this asynchronous method. The method must
* return a deferred or promise.
*
* Current-implementation is class-serialized (the mutex is common to all
* instances of the list view). Can be switched to instance-serialized if
* having concurrent list views becomes possible and common.
*/
function synchronized(fn) {
var fn_mutex = new $.Mutex();
return function () {
var args = _.toArray(arguments);
args.unshift(this);
return fn_mutex.exec(fn.bind.apply(fn, args));
};
}
var DataGroup = instance.web.Class.extend({
init: function(parent, model, domain, context, group_by, level) {
this.model = new instance.web.Model(model, context, domain);
@ -1648,6 +1674,10 @@ var DataGroup = instance.web.Class.extend({
},
list: function (fields, ifGroups, ifRecords) {
var self = this;
if (!_.isEmpty(this.group_by)) {
// ensure group_by fields are read.
fields = _.unique((fields || []).concat(this.group_by));
}
var query = this.model.query(fields).order_by(this.sort).group_by(this.group_by);
$.when(query).done(function (querygroups) {
// leaf node

View File

@ -427,12 +427,55 @@ ropenerp.testing.section('server-formats', {
date3.getUTCHours(), date3.getUTCMinutes(), date3.getUTCSeconds(), date3.getUTCMilliseconds()],
[2009, 5 - 1, 4, 12, 34, 23, 845]);
});
test('Parse server datetime on 31', {asserts: 1}, function() {
var wDate = window.Date;
var s = ropenerp.testing.Stack();
return s.push(function() {
window.Date = function(v) {
if (_.isUndefined(v)) {
v = '2013-10-31 12:34:56';
}
return new wDate(v);
};
}, function() {
window.Date = wDate;
}).execute(function() {
return openerp.str_to_datetime('2013-11-11 02:45:21');
}).then(function(date) {
deepEqual(
[date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(),
date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()],
[2013, 11 - 1, 11, 2, 45, 21]);
});
});
test('Parse server date', function () {
var date = openerp.str_to_date("2009-05-04");
deepEqual(
[date.getFullYear(), date.getMonth(), date.getDate()],
[2009, 5 - 1, 4]);
});
test('Parse server date on 31', {asserts: 1}, function() {
var wDate = window.Date;
var s = ropenerp.testing.Stack();
return s.push(function() {
window.Date = function(v) {
if (_.isUndefined(v)) {
v = '2013-10-31 12:34:56';
}
return new wDate(v);
};
}, function() {
window.Date = wDate;
}).execute(function() {
return openerp.str_to_date('2013-11-21');
}).then(function(date) {
deepEqual(
[date.getFullYear(), date.getMonth(), date.getDate()],
[2013, 11 - 1, 21]);
});
});
test('Parse server time', function () {
var date = openerp.str_to_time("12:34:23");
deepEqual(

View File

@ -239,7 +239,11 @@ instance.web_kanban.KanbanView = instance.web.View.extend({
self.$buttons.find('.oe_alternative').toggle(self.grouped_by_m2o);
self.$el.toggleClass('oe_kanban_grouped_by_m2o', self.grouped_by_m2o);
var grouping_fields = self.group_by ? [self.group_by].concat(_.keys(self.aggregates)) : undefined;
var grouping = new instance.web.Model(self.dataset.model, context, domain).query().group_by(grouping_fields);
if (!_.isEmpty(grouping_fields)) {
// ensure group_by fields are read.
self.fields_keys = _.unique(self.fields_keys.concat(grouping_fields));
}
var grouping = new instance.web.Model(self.dataset.model, context, domain).query(self.fields_keys).group_by(grouping_fields);
return self.alive($.when(grouping)).done(function(groups) {
self.remove_no_result();
if (groups) {