summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/views/basic/basic_model.js
diff options
context:
space:
mode:
authorGéry Debongnie <ged@odoo.com>2017-05-22 13:05:25 +0200
committerGéry Debongnie <ged@odoo.com>2017-05-22 14:25:30 +0200
commit4b8c34be15f355958bbdb64c440018bdbe72ad3c (patch)
treeab110709eaebea1e6ded91dd1729d1d624f46e79 /addons/web/static/src/js/views/basic/basic_model.js
parent967978c96ea1a30a5fd566cf26b1dec1c24e4013 (diff)
[FIX] web: properly evaluate context with x2m
The motivation for this commit was to fix a wrong evaluation context for x2m fields: it was using a list of res_id, which may contain virtual ids. For example, it could be seen in the form view for journal entries: adding the first line (field line_ids) was fine, but clicking on 'Add an item' a second time caused a crash. The reason was that the line_ids was explicitely added to the context in the view, and the second time we add a line, the web client sent a list looking like this [35, 'virtual_43'] to the server, in the nameget context. The proper behaviour is to send a list of commands for those fields. This means that we had to do some non trivial changes in the getEvalContext method: we stop using the get method with raw: true. It was nice to use the same method, but the eval context is actually different that the values returned by the get method. That was the motivation to introduce the 'noUnsetNumeric' flag, but now, we simply create another method and let each method do its own work. TLDR: eval contexts are hard...
Diffstat (limited to 'addons/web/static/src/js/views/basic/basic_model.js')
-rw-r--r--addons/web/static/src/js/views/basic/basic_model.js83
1 files changed, 63 insertions, 20 deletions
diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js
index 2895e5b2ff9..5d6a3271692 100644
--- a/addons/web/static/src/js/views/basic/basic_model.js
+++ b/addons/web/static/src/js/views/basic/basic_model.js
@@ -284,8 +284,6 @@ var BasicModel = AbstractModel.extend({
* @param {boolean} [options.env=false] if true, will only return res_id
* (if record) or res_ids (if list)
* @param {boolean} [options.raw=false] if true, will not follow relations
- * @param {boolean} [options.noUnsetNumeric=false] if true, will set numeric
- * values to 0 if not set
* @returns {Object}
*/
get: function (id, options) {
@@ -308,7 +306,6 @@ var BasicModel = AbstractModel.extend({
return env;
}
-
if (element.type === 'record') {
var data = _.extend({}, element.data, element._changes);
@@ -321,13 +318,6 @@ var BasicModel = AbstractModel.extend({
if (!field) {
continue;
}
- if (options.noUnsetNumeric) {
- if (field.type === 'float' ||
- field.type === 'integer' ||
- field.type === 'monetary') {
- data[fieldName] = data[fieldName] || 0;
- }
- }
// get relational datapoint
if (field.type === 'many2one') {
@@ -2067,19 +2057,23 @@ var BasicModel = AbstractModel.extend({
* @returns {Object}
*/
_getEvalContext: function (element) {
- var evalContext = this.get(element.id, {raw: true, noUnsetNumeric: true}).data;
- evalContext.active_model = element.model;
- evalContext.id = evalContext.id || false;
- evalContext.active_id = evalContext.id;
- evalContext.active_ids = evalContext.id ? [evalContext.id] : [];
+ var evalContext = element.type === 'record' ? this._getRecordEvalContext(element) : {};
+
if (element.parentID) {
- var parent = this.get(element.parentID, {raw: true});
- if (parent.type === 'list' && this.localData[element.parentID].parentID) {
- parent = this.get(this.localData[element.parentID].parentID, {raw: true});
+ var parent = this.localData[element.parentID];
+ if (parent.type === 'list' && parent.parentID) {
+ parent = this.localData[parent.parentID];
+ }
+ if (parent.type === 'record') {
+ evalContext.parent = this._getRecordEvalContext(parent);
}
- _.extend(evalContext, {parent: parent.data});
}
- return _.extend({}, session.user_context, element.context, evalContext);
+ return _.extend({
+ active_model: element.model,
+ id: evalContext.id || false,
+ active_id: evalContext.id || false,
+ active_ids: evalContext.id ? [evalContext.id] : [],
+ }, session.user_context, element.context, evalContext);
},
/**
* Returns the list of field names of the given element according to its
@@ -2093,6 +2087,55 @@ var BasicModel = AbstractModel.extend({
return Object.keys(fieldsInfo && fieldsInfo[element.viewType] || {});
},
/**
+ * Evaluate the record evaluation context. This method is supposed to be
+ * called by _getEvalContext. It basically only generates a dictionary of
+ * current values for the record, with commands for x2manys fields.
+ *
+ * @param {Object} record an element of type 'record'
+ * @returns Object
+ */
+ _getRecordEvalContext: function (record) {
+ var self = this;
+ var relDataPoint;
+ var context = _.extend({}, record.data, record._changes);
+ for (var fieldName in context) {
+ var field = record.fields[fieldName];
+ if (context[fieldName] === null) {
+ context[fieldName] = false;
+ }
+ if (!field) {
+ continue;
+ }
+ if (field.type === 'float' ||
+ field.type === 'integer' ||
+ field.type === 'monetary') {
+ context[fieldName] = context[fieldName] || 0;
+ continue;
+ }
+ if (field.type === 'many2one') {
+ relDataPoint = this.localData[context[fieldName]];
+ context[fieldName] = relDataPoint ? relDataPoint.res_id : false;
+ continue;
+ }
+ if (field.type === 'one2many' || field.type === 'many2many') {
+ relDataPoint = this.localData[context[fieldName]];
+ var relData = relDataPoint._changes || relDataPoint.data;
+ var commands = _.map(relData, function (id) {
+ var resID = self.localData[id].res_id;
+ if (typeof resID === 'string') {
+ var changes = self._generateChanges(self.localData[id]);
+ return x2ManyCommands.create(changes);
+ } else {
+ return x2ManyCommands.link_to(resID);
+ }
+ });
+ context[fieldName] = commands;
+ }
+
+ }
+ return context;
+ },
+ /**
* Returns true iff value is considered to be set for the given field's type.
*
* @private