[IMP] web, *: compute contexts and domains from datapoint
This commit tries to refactore the management of contexts and domains in the webclient. - Get rid of CompoundDomain: use standard array manipulation to join multiple domains or use the Domain class (to be improved) - Get rid of data.js build_domain and build_context methods - Link this.record to the data point from the basic model for all fields (not only relational fields) - Add a getContext and a getDomain function to the basic model data point (localData element) so that AbstractField implementations can use them thanks to their this.record element. - Remove the autocontext binding for field RPCs (see FieldManagerMixin)
This commit is contained in:
@@ -4,8 +4,8 @@ odoo.define('board.dashboard', function (require) {
|
||||
var ActionManager = require('web.ActionManager');
|
||||
var Context = require('web.Context');
|
||||
var core = require('web.core');
|
||||
var data = require('web.data');
|
||||
var Dialog = require('web.Dialog');
|
||||
var Domain = require('web.Domain');
|
||||
var FavoriteMenu = require('web.FavoriteMenu');
|
||||
var form_common = require('web.view_dialogs');
|
||||
var pyeval = require('web.pyeval');
|
||||
@@ -396,9 +396,11 @@ FavoriteMenu.include({
|
||||
|
||||
var search_data = this.searchview.build_search_data(),
|
||||
context = new Context(this.searchview.dataset.get_context() || []),
|
||||
domain = new data.CompoundDomain(this.searchview.dataset.get_domain() || []);
|
||||
domain = this.searchview.dataset.get_domain() || [];
|
||||
_.each(search_data.contexts, context.add, context);
|
||||
_.each(search_data.domains, domain.add, domain);
|
||||
_.each(search_data.domains, function (d) {
|
||||
domain.push(Domain.prototype.stringToArray(d));
|
||||
});
|
||||
|
||||
context.add({
|
||||
group_by: pyeval.eval('groupbys', search_data.groupbys || [])
|
||||
@@ -412,13 +414,12 @@ FavoriteMenu.include({
|
||||
}
|
||||
this.toggle_dashboard_menu(false);
|
||||
c.dashboard_merge_domains_contexts = false;
|
||||
var d = pyeval.eval('domain', domain);
|
||||
var name = self.$add_dashboard_input.val();
|
||||
|
||||
|
||||
return self.rpc('/board/add_to_dashboard', {
|
||||
action_id: self.action_id || false,
|
||||
context_to_save: c,
|
||||
domain: d,
|
||||
domain: domain,
|
||||
view_mode: self.view_manager.active_view.type,
|
||||
name: name,
|
||||
}).then(function (r) {
|
||||
|
||||
@@ -2,9 +2,9 @@ odoo.define('google_spreadsheet.google.spreadsheet', function (require) {
|
||||
"use strict";
|
||||
|
||||
var ActionManager = require('web.ActionManager');
|
||||
var Context = require('web.Context');
|
||||
var core = require('web.core');
|
||||
var data = require('web.data');
|
||||
var Domain = require('web.Domain');
|
||||
var FavoriteMenu = require('web.FavoriteMenu');
|
||||
var pyeval = require('web.pyeval');
|
||||
var ViewManager = require('web.ViewManager');
|
||||
@@ -14,7 +14,7 @@ var QWeb = core.qweb;
|
||||
FavoriteMenu.include({
|
||||
start: function () {
|
||||
this._super();
|
||||
var am = this.findAncestor(function(a) {
|
||||
var am = this.findAncestor(function (a) {
|
||||
return a instanceof ActionManager;
|
||||
});
|
||||
if (am && am.get_inner_widget() instanceof ViewManager) {
|
||||
@@ -28,17 +28,14 @@ FavoriteMenu.include({
|
||||
model = this.searchview.dataset.model,
|
||||
list_view = this.view_manager.views.list,
|
||||
list_view_id = list_view ? list_view.view_id : false,
|
||||
context = this.searchview.dataset.get_context() || [],
|
||||
compound_context = new Context(context),
|
||||
compound_domain = new data.CompoundDomain(context),
|
||||
domain = [],
|
||||
groupbys = pyeval.eval('groupbys', sv_data.groupbys).join(" "),
|
||||
ds = new data.DataSet(this, 'google.drive.config');
|
||||
|
||||
_.each(sv_data.contexts, compound_context.add, compound_context);
|
||||
_.each(sv_data.domains, compound_domain.add, compound_domain);
|
||||
|
||||
compound_domain = JSON.stringify(compound_domain.eval());
|
||||
ds.call('set_spreadsheet', [model, compound_domain, groupbys, list_view_id])
|
||||
_.each(sv_data.domains, function (d) {
|
||||
domain.push(Domain.prototype.stringToArray(d));
|
||||
});
|
||||
ds.call('set_spreadsheet', [model, Domain.prototype.arrayToString(domain), groupbys, list_view_id])
|
||||
.done(function (res) {
|
||||
if (res.url){
|
||||
window.open(res.url, '_blank');
|
||||
|
||||
@@ -6,7 +6,6 @@ var utils = require('mail.utils');
|
||||
var config = require('web.config');
|
||||
var Bus = require('web.Bus');
|
||||
var core = require('web.core');
|
||||
var data = require('web.data');
|
||||
var session = require('web.session');
|
||||
var time = require('web.time');
|
||||
var web_client = require('web.web_client');
|
||||
@@ -669,11 +668,11 @@ var ChatManager = Class.extend(Mixins.EventDispatcherMixin, Mixins.ServicesMixi
|
||||
var cache = get_channel_cache(channel, options.domain);
|
||||
|
||||
if (options.domain) {
|
||||
domain = new data.CompoundDomain(domain, options.domain || []).eval();
|
||||
domain = domain.concat(options.domain || []);
|
||||
}
|
||||
if (options.load_more) {
|
||||
var min_message_id = cache.messages[0].id;
|
||||
domain = new data.CompoundDomain([['id', '<', min_message_id]], domain).eval();
|
||||
domain = [['id', '<', min_message_id]].concat(domain);
|
||||
}
|
||||
|
||||
return this.rpc('mail.message', 'message_fetch')
|
||||
|
||||
@@ -217,7 +217,7 @@ var Followers = AbstractField.extend({
|
||||
_follow: function () {
|
||||
var kwargs = {
|
||||
partner_ids: [this.partnerID],
|
||||
context: {}, // new Context(this.build_context(), {}) // fixme
|
||||
context: {}, // FIXME
|
||||
};
|
||||
this.rpc(this.model, 'message_subscribe')
|
||||
.args([[this.res_id]])
|
||||
@@ -240,7 +240,7 @@ var Followers = AbstractField.extend({
|
||||
[self.res_id],
|
||||
ids.partner_ids,
|
||||
ids.channel_ids,
|
||||
{}, // new Context(self.build_context(), {}) // fixme
|
||||
{}, // FIXME
|
||||
];
|
||||
self.rpc(self.model, 'message_unsubscribe')
|
||||
.args(args)
|
||||
@@ -285,7 +285,7 @@ var Followers = AbstractField.extend({
|
||||
} else {
|
||||
var kwargs = _.extend({}, ids);
|
||||
kwargs.subtype_ids = checklist;
|
||||
kwargs.context = {}; // new Context(this.build_context(), {}); // fixme
|
||||
kwargs.context = {}; // FIXME
|
||||
this.rpc(this.model, 'message_subscribe')
|
||||
.args([[this.res_id]])
|
||||
.kwargs(kwargs)
|
||||
|
||||
@@ -64,8 +64,7 @@ var Query = Class.extend({
|
||||
if (!to_set.hasOwnProperty(key)) { continue; }
|
||||
switch(key) {
|
||||
case 'filter':
|
||||
q._filter = new CompoundDomain(
|
||||
q._filter, to_set.filter);
|
||||
q._filter = (q._filter || []).concat(to_set.filter || []);
|
||||
break;
|
||||
case 'context':
|
||||
q._context = new Context(
|
||||
@@ -729,77 +728,12 @@ var DataSetSearch = DataSet.extend({
|
||||
}
|
||||
});
|
||||
|
||||
var CompoundDomain = Class.extend({
|
||||
init: function () {
|
||||
this.__ref = "compound_domain";
|
||||
this.__domains = [];
|
||||
this.__eval_context = null;
|
||||
var self = this;
|
||||
_.each(arguments, function (x) {
|
||||
self.add(x);
|
||||
});
|
||||
},
|
||||
add: function (domain) {
|
||||
this.__domains.push(domain);
|
||||
return this;
|
||||
},
|
||||
set_eval_context: function (eval_context) {
|
||||
this.__eval_context = eval_context;
|
||||
return this;
|
||||
},
|
||||
get_eval_context: function () {
|
||||
return this.__eval_context;
|
||||
},
|
||||
eval: function () {
|
||||
return pyeval.eval('domain', this);
|
||||
},
|
||||
});
|
||||
|
||||
function rawify (data) {
|
||||
// replaces the value of relational fields by their raw value (the id, if
|
||||
// any, for many2ones and an array of ids for x2manys), in turn
|
||||
return _.mapObject(data, function (value) {
|
||||
if (value instanceof moment) {
|
||||
return moment;
|
||||
}
|
||||
if (_.isObject(value)) {
|
||||
return value.type === 'record' ? value.res_id : value.res_ids;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
function build_eval_context (record) {
|
||||
var field_values = rawify(_.extend({}, record.data, { active_model: record.model }));
|
||||
if ('id' in record.data) {
|
||||
field_values.active_id = record.data.id;
|
||||
field_values.active_ids = [record.data.id];
|
||||
}
|
||||
// FIXME: parent?
|
||||
return new Context(field_values);
|
||||
}
|
||||
|
||||
function build_context(record, context) {
|
||||
context = context || {};
|
||||
var eval_context = build_eval_context(record);
|
||||
return new Context(context).set_eval_context(eval_context);
|
||||
}
|
||||
|
||||
function build_domain(record, domain) {
|
||||
domain = domain || [];
|
||||
var eval_context = build_eval_context(record);
|
||||
return new CompoundDomain(domain).set_eval_context(eval_context);
|
||||
}
|
||||
|
||||
var data = {
|
||||
Query: Query,
|
||||
DataSet: DataSet,
|
||||
DataSetStatic: DataSetStatic,
|
||||
DataSetSearch: DataSetSearch,
|
||||
CompoundDomain: CompoundDomain,
|
||||
noDisplayContent: "<em class=\"text-warning\">" + _t("Unnamed") + "</em>",
|
||||
build_context: build_context,
|
||||
build_domain: build_domain,
|
||||
};
|
||||
|
||||
|
||||
@@ -841,11 +775,11 @@ var Model = Class.extend({
|
||||
* Fetches the model's domain, combined with the provided domain if any
|
||||
*
|
||||
* @param {Array} [domain] to combine with the model's internal domain
|
||||
* @returns {instance.web.CompoundDomain} The model's internal domain, or the AND-ed union of the model's internal domain and the provided domain
|
||||
* @returns {Array} The model's internal domain, or the AND-ed union of the model's internal domain and the provided domain
|
||||
*/
|
||||
domain: function (domain) {
|
||||
if (!domain) { return this._domain; }
|
||||
return new data.CompoundDomain(this._domain, domain);
|
||||
return this._domain.concat(domain);
|
||||
},
|
||||
/**
|
||||
* Fetches the combination of the user's context and the domain context,
|
||||
|
||||
@@ -3,7 +3,7 @@ odoo.define('web.search_inputs', function (require) {
|
||||
|
||||
var Context = require('web.Context');
|
||||
var core = require('web.core');
|
||||
var data = require('web.data');
|
||||
var Domain = require('web.Domain');
|
||||
var field_utils = require('web.field_utils');
|
||||
var pyeval = require('web.pyeval');
|
||||
var time = require('web.time');
|
||||
@@ -151,27 +151,27 @@ var Field = Input.extend( /** @lends instance.web.search.Field# */ {
|
||||
var domain = this.attrs.filter_domain;
|
||||
if (domain) {
|
||||
value_to_domain = function (facetValue) {
|
||||
return new data.CompoundDomain(domain)
|
||||
.set_eval_context({self: self.value_from(facetValue)});
|
||||
return Domain.prototype.stringToArray(
|
||||
domain,
|
||||
{self: self.value_from(facetValue)}
|
||||
);
|
||||
};
|
||||
} else {
|
||||
value_to_domain = function (facetValue) {
|
||||
return self.make_domain(
|
||||
self.attrs.name,
|
||||
self.attrs.operator || self.default_operator,
|
||||
facetValue);
|
||||
facetValue
|
||||
);
|
||||
};
|
||||
}
|
||||
var domains = facet.values.map(value_to_domain);
|
||||
|
||||
if (domains.length === 1) { return domains[0]; }
|
||||
for (var i = domains.length; --i;) {
|
||||
domains.unshift(['|']);
|
||||
if (domains.length === 1) {
|
||||
return domains[0];
|
||||
}
|
||||
|
||||
return _.extend(new data.CompoundDomain(), {
|
||||
__domains: domains
|
||||
});
|
||||
var ors = _.times(domains.length - 1, _.constant("|"));
|
||||
return ors.concat.apply(ors, domains);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -421,7 +421,7 @@ var ManyToOneField = CharField.extend({
|
||||
var args = this.attrs.domain;
|
||||
if (typeof args === 'string') {
|
||||
try {
|
||||
args = pyeval.eval('domain', args);
|
||||
args = Domain.prototype.stringToArray(args);
|
||||
} catch(e) {
|
||||
args = [];
|
||||
}
|
||||
@@ -625,14 +625,15 @@ var FilterGroup = Input.extend(/** @lends instance.web.search.FilterGroup# */{
|
||||
.reject(_.isEmpty)
|
||||
.value();
|
||||
|
||||
if (!domains.length) { return; }
|
||||
if (domains.length === 1) { return domains[0]; }
|
||||
for (var i=domains.length; --i;) {
|
||||
domains.unshift(['|']);
|
||||
if (!domains.length) {
|
||||
return;
|
||||
}
|
||||
return _.extend(new data.CompoundDomain(), {
|
||||
__domains: domains
|
||||
});
|
||||
if (domains.length === 1) {
|
||||
return domains[0];
|
||||
}
|
||||
|
||||
var ors = _.times(domains.length - 1, _.constant("|"));
|
||||
return ors.concat.apply(ors, domains);
|
||||
},
|
||||
toggle_filter: function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -14,6 +14,11 @@ var Context = Class.extend({
|
||||
self.add(x);
|
||||
});
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
add: function (context) {
|
||||
this.__contexts.push(context);
|
||||
return this;
|
||||
@@ -22,9 +27,6 @@ var Context = Class.extend({
|
||||
this.__eval_context = eval_context;
|
||||
return this;
|
||||
},
|
||||
get_eval_context: function () {
|
||||
return this.__eval_context;
|
||||
},
|
||||
eval: function () {
|
||||
return pyeval.eval('context', this);
|
||||
},
|
||||
|
||||
@@ -12,20 +12,22 @@ var Domain = collections.Tree.extend({
|
||||
/**
|
||||
* @constructor
|
||||
* @param {string|Array|boolean|undefined} domain
|
||||
* - The given domain can be:
|
||||
* The given domain can be:
|
||||
* * a string representation of the Python prefix-array
|
||||
* representation of the domain.
|
||||
* * a JS prefix-array representation of the domain.
|
||||
* * a boolean where the "true" domain match all records and the
|
||||
* "false" domain does not match any records.
|
||||
* * undefined, considered as the false boolean.
|
||||
* @param {Object} [evalContext] - in case the given domain is a string, an
|
||||
* evaluation context might be needed
|
||||
*/
|
||||
init: function (domain) {
|
||||
init: function (domain, evalContext) {
|
||||
this._super.apply(this, arguments);
|
||||
if (domain === true || domain === false || domain === undefined) {
|
||||
this._data = domain || false;
|
||||
} else {
|
||||
this._parse(this.normalizeArray(_.clone(this.stringToArray(domain))));
|
||||
this._parse(this.normalizeArray(_.clone(this.stringToArray(domain, evalContext))));
|
||||
}
|
||||
},
|
||||
|
||||
@@ -107,6 +109,30 @@ var Domain = collections.Tree.extend({
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {Array} JS prefix-array representation of this domain
|
||||
*/
|
||||
toArray: function () {
|
||||
if (this._data === false) {
|
||||
throw new Error("'false' domain cannot be converted to array");
|
||||
} else if (this._data === true) {
|
||||
return [];
|
||||
} else {
|
||||
var arr = [this._data];
|
||||
return arr.concat.apply(arr, _.map(this._children, function (child) {
|
||||
return child.toArray();
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {string} representation of the Python prefix-array
|
||||
* representation of the domain
|
||||
*/
|
||||
toString: function () {
|
||||
return Domain.prototype.arrayToString(this.toArray());
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -179,8 +205,9 @@ var Domain = collections.Tree.extend({
|
||||
arrayToString: function (domain) {
|
||||
if (_.isString(domain)) return domain;
|
||||
return JSON.stringify(domain || [])
|
||||
.replace(/false/g, "False")
|
||||
.replace(/true/g, "True");
|
||||
.replace(/null/g, "None")
|
||||
.replace(/false/g, "False")
|
||||
.replace(/true/g, "True");
|
||||
},
|
||||
/**
|
||||
* Converts a string representation of the Python prefix-array
|
||||
@@ -189,11 +216,12 @@ var Domain = collections.Tree.extend({
|
||||
*
|
||||
* @static
|
||||
* @param {string|Array} domain
|
||||
* @param {Object} [evalContext]
|
||||
* @returns {Array}
|
||||
*/
|
||||
stringToArray: function (domain) {
|
||||
stringToArray: function (domain, evalContext) {
|
||||
if (!_.isString(domain)) return domain;
|
||||
return pyeval.eval("domain", domain || "[]");
|
||||
return pyeval.eval("domain", domain || "[]", evalContext);
|
||||
},
|
||||
/**
|
||||
* Makes implicit "&" operators explicit in the given JS prefix-array
|
||||
|
||||
@@ -867,12 +867,6 @@ function eval_domains(domains, evaluation_context) {
|
||||
evaluation_context.context = evaluation_context;
|
||||
domain_array_to_combine = py.eval(domain.__debug, wrap_context(evaluation_context));
|
||||
break;
|
||||
case 'compound_domain':
|
||||
var eval_context = eval_contexts([domain.__eval_context]);
|
||||
domain_array_to_combine = eval_domains(
|
||||
domain.__domains, _.extend({}, evaluation_context, eval_context)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
domain_array_to_combine = domain;
|
||||
}
|
||||
@@ -983,7 +977,7 @@ function pyeval(type, object, context) {
|
||||
function eval_arg(arg) {
|
||||
if (typeof arg !== 'object' || !arg.__ref) { return arg; }
|
||||
switch(arg.__ref) {
|
||||
case 'domain': case 'compound_domain':
|
||||
case 'domain':
|
||||
return pyeval('domains', [arg]);
|
||||
case 'context': case 'compound_context':
|
||||
return pyeval('contexts', [arg]);
|
||||
|
||||
@@ -81,6 +81,9 @@ var AbstractField = Widget.extend({
|
||||
// 'name' is the field name displayed by this widget
|
||||
this.name = name;
|
||||
|
||||
// the datapoint fetched from the model
|
||||
this.record = record;
|
||||
|
||||
// the 'field' property is a description of all the various field properties,
|
||||
// such as the type, the comodel (relation), ...
|
||||
this.field = record.fields[name];
|
||||
@@ -208,17 +211,6 @@ var AbstractField = Widget.extend({
|
||||
this._reset(record, event);
|
||||
return this._render();
|
||||
},
|
||||
/**
|
||||
* @override performModelRPC from ServicesMixin
|
||||
* Adds the dataPointID to the option parameter so that the BasicController
|
||||
* (the FieldManagerMixin) knows the context to bind to the rpc call.
|
||||
*/
|
||||
performModelRPC: function (model, method, args, kwargs, options) {
|
||||
return this._super(model, method, args, kwargs, _.extend({
|
||||
dataPointID: this.dataPointID,
|
||||
fieldName: this.name,
|
||||
}, options || {}));
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
@@ -289,6 +281,7 @@ var AbstractField = Widget.extend({
|
||||
* @param {OdooEvent} event the event that triggered the change
|
||||
*/
|
||||
_reset: function (record, event) {
|
||||
this.record = record;
|
||||
this.value = record.data[this.name];
|
||||
this.recordData = record.data;
|
||||
},
|
||||
|
||||
@@ -1298,9 +1298,9 @@ var FieldDomain = AbstractField.extend({
|
||||
// ... then query the model to get the number of matched record if valid
|
||||
var self = this;
|
||||
return def.then(function () {
|
||||
var context = {}; // FIXME ?
|
||||
return self.rpc(self.domainModel, "search_count")
|
||||
.args([domain,context])
|
||||
.args([domain])
|
||||
.kwargs({context: self.record.getContext({fieldName: self.name})})
|
||||
.exec()
|
||||
.then(function (data) {
|
||||
self._isValidForModel = true;
|
||||
|
||||
@@ -16,7 +16,6 @@ odoo.define('web.relational_fields', function (require) {
|
||||
var AbstractField = require('web.AbstractField');
|
||||
var concurrency = require('web.concurrency');
|
||||
var config = require('web.config');
|
||||
var Context = require('web.Context');
|
||||
var ControlPanel = require('web.ControlPanel');
|
||||
var dialogs = require('web.view_dialogs');
|
||||
var core = require('web.core');
|
||||
@@ -26,39 +25,10 @@ var field_utils = require('web.field_utils');
|
||||
var KanbanRenderer = require('web.KanbanRenderer');
|
||||
var ListRenderer = require('web.ListRenderer');
|
||||
var Pager = require('web.Pager');
|
||||
var pyeval = require('web.pyeval');
|
||||
|
||||
var _t = core._t;
|
||||
var qweb = core.qweb;
|
||||
|
||||
/**
|
||||
* Abstract widget to handle relational fields
|
||||
*/
|
||||
var AbstractRelationalField = AbstractField.extend({
|
||||
init: function (parent, name, record) {
|
||||
this._super.apply(this, arguments);
|
||||
// 'domain' and 'context' that should be used by the field widget. It
|
||||
// can come from the attrs, and is mostly useful for rpcs
|
||||
this.domain = this.attrs.domain || this.field.domain || [];
|
||||
this.context = this.attrs.context || this.field.context || {};
|
||||
|
||||
// todo: remove this
|
||||
this.record = record;
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_reset: function (record) {
|
||||
this.record = record;
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Many2one widgets
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -104,7 +74,7 @@ var M2ODialog = Dialog.extend({
|
||||
},
|
||||
});
|
||||
|
||||
var FieldMany2One = AbstractRelationalField.extend({
|
||||
var FieldMany2One = AbstractField.extend({
|
||||
template: 'FieldMany2One',
|
||||
custom_events: {
|
||||
'quick_create': '_onQuickCreate',
|
||||
@@ -229,6 +199,7 @@ var FieldMany2One = AbstractRelationalField.extend({
|
||||
if (this.nodeOptions.quick_create) {
|
||||
this.rpc(this.field.relation, "name_create")
|
||||
.args([name])
|
||||
.kwargs({context: this.record.getContext({fieldName: this.name})})
|
||||
.exec()
|
||||
.then(function (result) {
|
||||
if (self.mode === "edit") {
|
||||
@@ -288,18 +259,20 @@ var FieldMany2One = AbstractRelationalField.extend({
|
||||
var def = $.Deferred();
|
||||
this.orderer.add(def);
|
||||
|
||||
var exclusion_domain = [];
|
||||
var context = this.record.getContext({fieldName: this.name});
|
||||
var domain = this.record.getDomain({fieldName: this.name});
|
||||
|
||||
var blacklisted_ids = this._getSearchBlacklist();
|
||||
if (blacklisted_ids.length > 0) {
|
||||
exclusion_domain.push(['id', 'not in', blacklisted_ids]);
|
||||
domain.push(['id', 'not in', blacklisted_ids]);
|
||||
}
|
||||
var domain = new data.CompoundDomain(data.build_domain(this.record, this.domain), exclusion_domain);
|
||||
|
||||
this.performModelRPC(this.field.relation, "name_search", [], {
|
||||
name: search_val,
|
||||
args: pyeval.eval("domain", domain),
|
||||
args: domain,
|
||||
operator: "ilike",
|
||||
limit: this.limit + 1,
|
||||
context: context,
|
||||
}).then(function (result) {
|
||||
// possible selections for the m2o
|
||||
var values = _.map(result, function (x) {
|
||||
@@ -320,9 +293,10 @@ var FieldMany2One = AbstractRelationalField.extend({
|
||||
action: function () {
|
||||
self.performModelRPC(self.field.relation, "name_search", {
|
||||
name: search_val,
|
||||
args: pyeval.eval('domain', domain),
|
||||
args: domain,
|
||||
operator: "ilike",
|
||||
limit: 160,
|
||||
context: context,
|
||||
}).then(self._searchCreatePopup.bind(self, "search"));
|
||||
},
|
||||
classname: 'o_m2o_dropdown_option',
|
||||
@@ -370,8 +344,8 @@ var FieldMany2One = AbstractRelationalField.extend({
|
||||
var self = this;
|
||||
new dialogs.SelectCreateDialog(this, _.extend({}, this.nodeOptions, {
|
||||
res_model: this.field.relation,
|
||||
domain: data.build_domain(this.record, this.domain),
|
||||
context: new Context(data.build_context(this.record, this.context), context || {}),
|
||||
domain: this.record.getDomain({fieldName: this.name}),
|
||||
context: _.extend({}, this.record.getContext({fieldName: this.name}), context || {}),
|
||||
title: (view === 'search' ? _t("Search: ") : _t("Create: ")) + this.string,
|
||||
initial_ids: ids ? _.map(ids, function (x) { return x[0]; }) : undefined,
|
||||
initial_view: view,
|
||||
@@ -405,12 +379,13 @@ var FieldMany2One = AbstractRelationalField.extend({
|
||||
if (this.mode === 'readonly' && !this.nodeOptions.no_open) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
var context = data.build_context(this.record, this.context);
|
||||
var args = [[this.value.res_id], context.eval()];
|
||||
this.performModelRPC(this.field.relation, 'get_formview_action', args)
|
||||
.then(function (action) {
|
||||
self.trigger_up('do_action', {action: action});
|
||||
});
|
||||
this.performModelRPC(this.field.relation, 'get_formview_action', [
|
||||
[this.value.res_id]
|
||||
], {
|
||||
context: this.record.getContext({fieldName: this.name}),
|
||||
}).then(function (action) {
|
||||
self.trigger_up('do_action', {action: action});
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -422,11 +397,14 @@ var FieldMany2One = AbstractRelationalField.extend({
|
||||
return;
|
||||
}
|
||||
var self = this;
|
||||
var context = data.build_context(this.record, this.context);
|
||||
var model = this.field.relation;
|
||||
var method = 'get_formview_id';
|
||||
var args = [[this.value.res_id], context.eval()];
|
||||
this.performModelRPC(model, method, args).then(function (view_id) {
|
||||
var context = this.record.getContext({fieldName: this.name});
|
||||
this.performModelRPC(model, method, [
|
||||
[this.value.res_id]
|
||||
], {
|
||||
context: context,
|
||||
}).then(function (view_id) {
|
||||
new dialogs.FormViewDialog(self, {
|
||||
res_model: self.field.relation,
|
||||
res_id: self.value.res_id,
|
||||
@@ -492,7 +470,7 @@ var ListFieldMany2One = FieldMany2One.extend({
|
||||
},
|
||||
});
|
||||
|
||||
var KanbanFieldMany2One = AbstractRelationalField.extend({
|
||||
var KanbanFieldMany2One = AbstractField.extend({
|
||||
tagName: 'span',
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
@@ -515,9 +493,9 @@ var KanbanFieldMany2One = AbstractRelationalField.extend({
|
||||
// X2Many widgets
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
var FieldX2Many = AbstractRelationalField.extend({
|
||||
var FieldX2Many = AbstractField.extend({
|
||||
tagName: 'div',
|
||||
custom_events: _.extend({}, AbstractRelationalField.prototype.custom_events, {
|
||||
custom_events: _.extend({}, AbstractField.prototype.custom_events, {
|
||||
field_changed: '_onFieldChanged',
|
||||
kanban_record_delete: '_onDeleteRecord',
|
||||
list_record_delete: '_onDeleteRecord',
|
||||
@@ -716,8 +694,8 @@ var FieldX2Many = AbstractRelationalField.extend({
|
||||
*/
|
||||
_onOpenRecord: function (event) {
|
||||
_.extend(event.data, {
|
||||
context: data.build_context(this.record, this.context),
|
||||
domain: data.build_context(this.record, this.domain),
|
||||
context: this.record.getContext({fieldName: this.name}),
|
||||
domain: this.record.getDomain({fieldName: this.name}),
|
||||
form_view: this.field.views && this.field.views.form,
|
||||
readonly: this.mode === 'readonly',
|
||||
string: this.string,
|
||||
@@ -810,8 +788,8 @@ var FieldOne2Many = FieldX2Many.extend({
|
||||
});
|
||||
} else {
|
||||
this.trigger_up('add_one2many_record', {
|
||||
domain: data.build_domain(this.record, this.domain),
|
||||
context: data.build_context(this.record, this.context),
|
||||
domain: this.record.getDomain({fieldName: this.name}),
|
||||
context: this.record.getContext({fieldName: this.name}),
|
||||
field: this.field,
|
||||
on_save: function (record) {
|
||||
this._setValue({
|
||||
@@ -872,11 +850,13 @@ var FieldMany2Many = FieldX2Many.extend({
|
||||
*/
|
||||
_onAddRecord: function () {
|
||||
var self = this;
|
||||
var domain = data.build_domain(this.record, this.domain);
|
||||
|
||||
var domain = this.record.getDomain({fieldName: this.name});
|
||||
|
||||
new dialogs.SelectCreateDialog(this, {
|
||||
res_model: this.field.relation,
|
||||
domain: new data.CompoundDomain(domain, ["!", ["id", "in", this.value.res_ids]]),
|
||||
context: data.build_context(this.record, this.context),
|
||||
domain: domain.concat(["!", ["id", "in", this.value.res_ids]]),
|
||||
context: this.record.getContext({fieldName: this.name}),
|
||||
title: _t("Add: ") + this.string,
|
||||
no_create: this.nodeOptions.no_create || !this.activeActions.create,
|
||||
on_selected: function (res_ids) {
|
||||
@@ -908,7 +888,7 @@ var FieldMany2Many = FieldX2Many.extend({
|
||||
},
|
||||
});
|
||||
|
||||
var FieldMany2ManyTags = AbstractRelationalField.extend({
|
||||
var FieldMany2ManyTags = AbstractField.extend({
|
||||
tag_template: "FieldMany2ManyTag",
|
||||
className: "o_form_field o_form_field_many2manytags",
|
||||
replace_element: true,
|
||||
@@ -1118,9 +1098,9 @@ var FormFieldMany2ManyTags = FieldMany2ManyTags.extend({
|
||||
},
|
||||
});
|
||||
|
||||
var FieldMany2ManyCheckBoxes = AbstractRelationalField.extend({
|
||||
var FieldMany2ManyCheckBoxes = AbstractField.extend({
|
||||
template: 'FieldMany2ManyCheckBoxes',
|
||||
events: _.extend({}, AbstractRelationalField.prototype.events, {
|
||||
events: _.extend({}, AbstractField.prototype.events, {
|
||||
change: '_onChange',
|
||||
}),
|
||||
supportedFieldTypes: ['many2many'],
|
||||
|
||||
@@ -79,7 +79,7 @@ odoo.define('web.BasicModel', function (require) {
|
||||
var AbstractModel = require('web.AbstractModel');
|
||||
var concurrency = require('web.concurrency');
|
||||
var Context = require('web.Context');
|
||||
var data = require('web.data'); // TODO: remove dependency to data.js
|
||||
var Domain = require('web.Domain');
|
||||
var fieldUtils = require('web.field_utils');
|
||||
var pyeval = require('web.pyeval');
|
||||
var session = require('web.session');
|
||||
@@ -365,6 +365,10 @@ var BasicModel = AbstractModel.extend({
|
||||
delete element.parentID;
|
||||
delete element.relation_field;
|
||||
delete element.rawContext;
|
||||
|
||||
element.getContext = this._getContext.bind(this, record);
|
||||
element.getDomain = this._getDomain.bind(this, record);
|
||||
|
||||
return element;
|
||||
},
|
||||
/**
|
||||
@@ -929,20 +933,6 @@ var BasicModel = AbstractModel.extend({
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Every RPC done by the model need to add some context, which is a
|
||||
* combination of the context of the session, of the record/list, and/or of
|
||||
* the concerned field. This method combines all these contexts and evaluate
|
||||
* them with the proper evalcontext.
|
||||
*
|
||||
* @param {string} recordID - the id of an element from the localData
|
||||
* @see _getContext for the options parameter
|
||||
* @returns {Object} the evaluated context
|
||||
*/
|
||||
getContext: function (recordID, options) {
|
||||
var record = this.localData[recordID];
|
||||
return this._getContext(record, options);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
@@ -1626,7 +1616,77 @@ var BasicModel = AbstractModel.extend({
|
||||
*/
|
||||
_getContext: function (element, options) {
|
||||
var context = new Context(session.user_context, element.context);
|
||||
context.set_eval_context(this._getEvalContext(element));
|
||||
|
||||
if (options && options.fieldName) {
|
||||
var attrs = element.fieldAttrs[options.fieldName];
|
||||
if (attrs && attrs.context) {
|
||||
context.add(attrs.context);
|
||||
} else {
|
||||
var fieldParams = element.fields[options.fieldName];
|
||||
if (fieldParams.context) {
|
||||
context.add(fieldParams.context);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (element.rawContext) {
|
||||
var rawContext = new Context(element.rawContext);
|
||||
var evalContext = this._getEvalContext(this.localData[element.parentID]);
|
||||
evalContext.id = evalContext.id || false;
|
||||
rawContext.set_eval_context(evalContext);
|
||||
context.add(rawContext);
|
||||
}
|
||||
|
||||
return context.eval();
|
||||
},
|
||||
/**
|
||||
* Some records are associated to a/some domain(s). This method allows to
|
||||
* retrieve them, evaluated.
|
||||
*
|
||||
* @param {Object} element an element from the localData
|
||||
* @param {Object} [options]
|
||||
* @param {string} [options.fieldName]
|
||||
* the name of the field whose domain needs to be returned
|
||||
* @returns {Array} the evaluated domain
|
||||
*/
|
||||
_getDomain: function (element, options) {
|
||||
if (options && options.fieldName) {
|
||||
var attrs = element.fieldAttrs[options.fieldName];
|
||||
if (attrs && attrs.domain) {
|
||||
return Domain.prototype.stringToArray(
|
||||
attrs.domain,
|
||||
this._getEvalContext(element)
|
||||
);
|
||||
}
|
||||
var fieldParams = element.fields[options.fieldName];
|
||||
if (fieldParams.domain) {
|
||||
return Domain.prototype.stringToArray(
|
||||
fieldParams.domain,
|
||||
this._getEvalContext(element)
|
||||
);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
return Domain.prototype.stringToArray(
|
||||
element.domain,
|
||||
this._getEvalContext(element)
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Returns the evaluation context that should be used when evaluating the
|
||||
* context/domain associated to a given element from the localData.
|
||||
*
|
||||
* @param {Object} element - an element from the localData
|
||||
* @returns {Object}
|
||||
*/
|
||||
_getEvalContext: function (element) {
|
||||
var evalContext = this.get(element.id, {raw: true}).data;
|
||||
evalContext.active_model = element.model;
|
||||
if (evalContext.id) {
|
||||
evalContext.active_id = evalContext.id;
|
||||
evalContext.active_ids = [evalContext.id];
|
||||
}
|
||||
if (element.parentID) {
|
||||
var parent = this.get(element.parentID, {raw: true});
|
||||
if (parent.type === 'list' && this.localData[element.parentID].parentID) {
|
||||
@@ -1634,23 +1694,7 @@ var BasicModel = AbstractModel.extend({
|
||||
}
|
||||
_.extend(evalContext, {parent: parent.data});
|
||||
}
|
||||
context.set_eval_context(evalContext);
|
||||
if (options && options.fieldName) {
|
||||
var attrs = element.fieldAttrs[options.fieldName];
|
||||
if (attrs && attrs.context) {
|
||||
context.add(attrs.context);
|
||||
}
|
||||
}
|
||||
|
||||
if (element.rawContext) {
|
||||
var rawContext = new Context(element.rawContext);
|
||||
var evalContext = this.get(element.parentID, {raw: true}).data;
|
||||
evalContext.id = evalContext.id || false;
|
||||
rawContext.set_eval_context(evalContext);
|
||||
context.add(rawContext);
|
||||
}
|
||||
|
||||
return context.eval();
|
||||
return evalContext;
|
||||
},
|
||||
/**
|
||||
* Helper method for the load entry point.
|
||||
@@ -1759,8 +1803,7 @@ var BasicModel = AbstractModel.extend({
|
||||
}
|
||||
return val;
|
||||
});
|
||||
var _domain = new data.CompoundDomain(field.domain || {}).set_eval_context(field_values);
|
||||
var domain = pyeval.eval('domain', _domain);
|
||||
var domain = Domain.prototype.stringToArray(field.domain || [], field_values);
|
||||
var fold_field = pyeval.py_eval(attrs.options || '{}').fold_field;
|
||||
var fetch_status_information = self.rpc(field.relation, 'search_read')
|
||||
.withFields(['id'].concat(fold_field ? [fold_field] : []))
|
||||
|
||||
@@ -18,7 +18,6 @@ var FieldManagerMixin = {
|
||||
custom_events: {
|
||||
field_changed: '_onFieldChanged',
|
||||
load: '_onLoad',
|
||||
call_service: '_onCallService',
|
||||
},
|
||||
/**
|
||||
* A FieldManagerMixin can be initialized with an instance of a basicModel.
|
||||
@@ -114,40 +113,6 @@ var FieldManagerMixin = {
|
||||
data.on_success(self.model.get(db_id));
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Some widgets perform model RPCs. These are intercepted so that the
|
||||
* context can be automatically added according to the given dataPointID
|
||||
* option the AbstractField implementation automatically adds.
|
||||
*
|
||||
* @param {OdooEvent} e
|
||||
* @param {string} e.data.service - the service called, here we are only
|
||||
* interested in the "ajax" service
|
||||
* @param {string} e.data.method - the service method called, here we are
|
||||
* only interested by the "rpc" method
|
||||
* @param {Array} e.data.args
|
||||
* the args parameters contains the route, the route arguments and
|
||||
* the RPC call options. This method purpose is to check the RPC
|
||||
* call options for the dataPointID (and field name) and merge the
|
||||
* appropriate context with the route arguments' one.
|
||||
*/
|
||||
_onCallService: function (e) {
|
||||
if (e.data.service !== "ajax" || e.data.method !== "rpc") {
|
||||
return;
|
||||
}
|
||||
|
||||
var args = e.data.args[1];
|
||||
var options = e.data.args[2];
|
||||
if (args.kwargs && options.dataPointID) {
|
||||
args.kwargs.context = _.extend(
|
||||
this.model.getContext(options.dataPointID, {
|
||||
fieldName: options.fieldName || false,
|
||||
}),
|
||||
args.kwargs.context || {}
|
||||
);
|
||||
// to prevent doing this work again, in some other widget with FMM.
|
||||
delete options.dataPointID;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return FieldManagerMixin;
|
||||
|
||||
@@ -243,7 +243,7 @@ var FormController = BasicController.extend({
|
||||
var recordID = record.data.id;
|
||||
this.trigger_up('execute_action', {
|
||||
action_data: _.extend({}, attrs, {
|
||||
context: data.build_context(record, attrs.context)
|
||||
context: _.extend(record.getContext(), attrs.context),
|
||||
}),
|
||||
model: record.model,
|
||||
record_id: recordID,
|
||||
@@ -532,7 +532,7 @@ var FormController = BasicController.extend({
|
||||
res_model: model,
|
||||
res_id: res_id,
|
||||
fields_view: form_fields_view,
|
||||
context: data.build_context(record),
|
||||
context: record.getContext(),
|
||||
readonly: event.data.readonly,
|
||||
title: _t("Open: ") + event.data.string,
|
||||
on_save: event.data.on_save,
|
||||
@@ -605,7 +605,7 @@ return FormController;
|
||||
// record = record || this.model.get(this.db_id);
|
||||
// var record_id = record.data.id;
|
||||
// this.trigger_up('execute_action', {
|
||||
// action_data: _.extend({}, attrs, { context: data.build_context(record, attrs.context) }),
|
||||
// action_data: _.extend({}, attrs, { context: _.extend(record.getContext(), attrs.context) }),
|
||||
// dataset: this.dataset,
|
||||
// record_id: record_id,
|
||||
// on_close: function (reason) {
|
||||
|
||||
@@ -281,13 +281,13 @@ QUnit.module('core', function () {
|
||||
}, /^Error: TypeError:/); //20
|
||||
assert.throws(function () {
|
||||
py.eval('a - 1', ctx);
|
||||
}, /^Error: TypeError:/);
|
||||
}, /^Error: TypeError:/);
|
||||
assert.throws(function () {
|
||||
py.eval('1 + a', ctx);
|
||||
}, /^Error: TypeError:/);
|
||||
}, /^Error: TypeError:/);
|
||||
assert.throws(function () {
|
||||
py.eval('1 - a', ctx);
|
||||
}, /^Error: TypeError:/);
|
||||
}, /^Error: TypeError:/);
|
||||
|
||||
// delta - date is senseless.
|
||||
assert.throws(function () {
|
||||
@@ -451,7 +451,7 @@ QUnit.module('core', function () {
|
||||
{ "active_id": 9, "active_ids": [ 9 ], "active_model": "mail.compose.message" }
|
||||
];
|
||||
var result = pyEval.eval_domains_and_contexts({
|
||||
contexts: ctx,
|
||||
contexts: ctx,
|
||||
domins: [],
|
||||
});
|
||||
|
||||
@@ -522,10 +522,7 @@ QUnit.module('core', function () {
|
||||
var result = pyEval.eval_domains_and_contexts({
|
||||
domains: [
|
||||
[['type', '=', 'contract']],
|
||||
{ "__domains": [["|"], [["state", "in", ["open", "draft"]]], [["type", "=", "contract"], ["state", "=", "pending"]]],
|
||||
"__eval_context": null,
|
||||
"__ref": "compound_domain"
|
||||
},
|
||||
["|", ["state", "in", ["open", "draft"]], [["type", "=", "contract"], ["state", "=", "pending"]]],
|
||||
"['|', '&', ('date', '!=', False), ('date', '<=', time.strftime('%Y-%m-%d')), ('is_overdue_quantity', '=', True)]",
|
||||
[['user_id', '=', 1]]
|
||||
],
|
||||
@@ -562,14 +559,11 @@ QUnit.module('core', function () {
|
||||
});
|
||||
assert.deepEqual(result1.domain, [['company_id', '=', false]]);
|
||||
|
||||
var compound_domain = new data.CompoundDomain(d);
|
||||
compound_domain.set_eval_context({company_id: 42});
|
||||
|
||||
var result2 = pyEval.eval_domains_and_contexts({
|
||||
domains: [compound_domain],
|
||||
domains: [d],
|
||||
contexts: [],
|
||||
eval_context: {company_id: 42},
|
||||
});
|
||||
|
||||
assert.deepEqual(result2.domain, [['company_id', '=', 42]]);
|
||||
});
|
||||
|
||||
@@ -1014,4 +1008,3 @@ QUnit.module('core', function () {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -437,8 +437,8 @@ QUnit.module('relational_fields', {
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('check that the field context is used when doing a name_search in a m2o', function (assert) {
|
||||
assert.expect(3);
|
||||
QUnit.test('domain and context are correctly used when doing a name_search in a m2o', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
@@ -446,20 +446,24 @@ QUnit.module('relational_fields', {
|
||||
data: this.data,
|
||||
arch:
|
||||
'<form string="Partners">' +
|
||||
'<field name="product_id" context="{\'hello\': \'world\', \'test\': foo}"/>' +
|
||||
'<field name="product_id" ' +
|
||||
'domain="[[\'foo\', \'=\', \'bar\'], [\'foo\', \'=\', foo]]" ' +
|
||||
'context="{\'hello\': \'world\', \'test\': foo}"/>' +
|
||||
'<field name="foo"/>' +
|
||||
'</form>',
|
||||
res_id: 1,
|
||||
session: {user_context: {hey: "ho"}},
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/web/dataset/call_kw/product/name_search') {
|
||||
var context = args.kwargs.context;
|
||||
assert.strictEqual(context.hey, "ho",
|
||||
'the session context should have been used for the rpc');
|
||||
assert.strictEqual(context.hello, "world",
|
||||
'the field context should have been used for the RPC');
|
||||
assert.strictEqual(context.test, "yop",
|
||||
'the field context should have been properly evaluated');
|
||||
assert.deepEqual(
|
||||
args.kwargs.args,
|
||||
[['foo', '=', 'bar'], ['foo', '=', 'yop']],
|
||||
'the field attr domain should have been used for the RPC (and evaluated)');
|
||||
assert.deepEqual(
|
||||
args.kwargs.context,
|
||||
{hey: "ho", hello: "world", test: "yop"},
|
||||
'the field attr context should have been used for the '
|
||||
+ 'RPC (evaluated and merged with the session one)');
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
@@ -638,7 +638,6 @@ QUnit.module('Views', {
|
||||
model.destroy();
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('write commands on a one2many', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
@@ -835,5 +834,64 @@ QUnit.module('Views', {
|
||||
model.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('contexts and domains can be properly fetched', function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
this.data.partner.fields.product_id.context = "{'hello': 'world', 'test': foo}";
|
||||
this.data.partner.fields.product_id.domain = "[['hello', 'like', 'world'], ['test', 'like', foo]]";
|
||||
|
||||
var model = createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
|
||||
this.params.fieldNames = ['product_id', 'foo'];
|
||||
|
||||
model.load(this.params).then(function (resultID) {
|
||||
var recordPartner = model.get(resultID);
|
||||
assert.strictEqual(typeof recordPartner.getContext, "function",
|
||||
"partner record should have a getContext function");
|
||||
assert.strictEqual(typeof recordPartner.getDomain, "function",
|
||||
"partner record should have a getDomain function");
|
||||
assert.deepEqual(recordPartner.getContext(), {},
|
||||
"asking for a context without a field name should fetch the session/user/view context");
|
||||
assert.deepEqual(recordPartner.getDomain(), [],
|
||||
"asking for a domain without a field name should fetch the session/user/view domain");
|
||||
assert.deepEqual(
|
||||
recordPartner.getContext({fieldName: "product_id"}),
|
||||
{hello: "world", test: "gnap"},
|
||||
"asking for a context with a field name should fetch the field context (evaluated)");
|
||||
assert.deepEqual(
|
||||
recordPartner.getDomain({fieldName: "product_id"}),
|
||||
[["hello", "like", "world"], ["test", "like", "gnap"]],
|
||||
"asking for a domain with a field name should fetch the field domain (evaluated)");
|
||||
});
|
||||
model.destroy();
|
||||
|
||||
// Try again with xml override of field domain and context
|
||||
model = createModel({
|
||||
Model: BasicModel,
|
||||
data: this.data,
|
||||
});
|
||||
|
||||
this.params.fieldAttrs = {
|
||||
product_id: {
|
||||
context: "{'hello2': 'world', 'test2': foo}",
|
||||
domain: "[['hello2', 'like', 'world'], ['test2', 'like', foo]]",
|
||||
},
|
||||
};
|
||||
|
||||
model.load(this.params).then(function (resultID) {
|
||||
var recordPartner = model.get(resultID);
|
||||
assert.deepEqual(
|
||||
recordPartner.getContext({fieldName: "product_id"}),
|
||||
{hello2: "world", test2: "gnap"},
|
||||
"field context should have been overriden by xml attribute");
|
||||
assert.deepEqual(
|
||||
recordPartner.getDomain({fieldName: "product_id"}),
|
||||
[["hello2", "like", "world"], ["test2", "like", "gnap"]],
|
||||
"field domain should have been overriden by xml attribute");
|
||||
});
|
||||
model.destroy();
|
||||
});
|
||||
});});
|
||||
|
||||
Reference in New Issue
Block a user